Andres Bernal

Andres Bernal

Developer.

© 2019

API REST con NODEJS y EXPRESS

OOP

Con API REST enviamo y recibimos datos de forma sencilla y rápida, aunque una tecnología que está en crecimiento es el GraphQL que busca reemplazar a las API REST para hacerlas aún más sencillas y a la vez más robustas.Escribire mas adelante sobre esto.

Las API REST usa los métodos HTTP, desde un simple POST o GET hasta métodos personalizados, los mas usados son POST, GET, PUT y DELETE en su forma más sencilla y las Headers que son para autenticación, decirle qué tipo de dato va, etc. Pero esto no lo veremos aquí.

Usare a Express para ser nuestro servidor HTTP, una recomendación es que, las API REST siempre estén detrás de Nginx ya que en caso de falla, Nginx puede seguir respondiendo, además que, permite una mejor manipulación de datos, protección de enlaces y demás.

Bueno, si ya tenemos NodeJS y NPM instalados, entonces manos a la obra y si no, https://nodejs.org/es/download/ aquí pueden descargar el paquete, el proceso de instalación

♠️ Crear app

Para inicializar nuestra primer API REST hay 3 modos, creando el package.json a mano (no recomendado), haciendo uso del comando npm init (de cierta forma el más recomendado) o usando la dependencia de express-generator pero en esta ocasión haremos uso del npm init para ello, nos ponemos en la consola de comandos (Linux, Windows o Mac, en mi caso Windows) y navegamos al directorio donde queremos que esté nuestra API REST, en mi caso, mi carpeta de Documentos en una carpeta llamada, api . Dentro de esta carpeta corremos el comando previamente mencionado y nos irán apareciendo una serie de preguntas:

Primero nos pedirá el nombre del paquete (en si, es el nombre de nuestro proyecto), aquí ponemos api-rest Después nos pedirá la versión del proyecto, pondremos 1.0.0

En descripción pondremos “API REST ejemplo”.

Luego en la parte de entry point nos pide cómo se llamará nuestro archivo de entrada, el principal digamos. Dejaremos index.js tal cual.

Después nos pide un comando de prueba, un repositorio de git, palabras clave que dejaremos vacías, solo damos enter. La parte de autor, ponemos nuestro nombre si somos lo autores del paquete.

Por último nos pedira una licencia, pondremos MIT (aunque también se puede dejar la que está o poner Private), no es relevante a menos que vayan a liberar su API REST por alguna razón.

Una vez que tenemos esto, nos dice, ¿Está todo correcto? y le decimos que si dando enter.

Si funciona correctamente, se generará en nuestra carpeta nuestro archivo package.json y si es así, entonces sigue instalar Express, para ello corremos el siguiente comando:

npm install express --save

Con esto, la dependencia de express se instala y se guarda en nuestro package y estamos listos para empezar.

♠️ Primeros pasos API

Como había escrito previamente a la hora de inicializar nuestro proyecto, decidimos que nuestro archivo de entrada se llamara index.jsy es por ello que entonces crearemos este archivo en la carpeta raíz .../Documents/api/index.js` y dentro le pondremos el siguiente código:

const express = require("express");
const app = express();app.listen(3000, () => {
 console.log("El servidor está inicializado en el puerto 3000");
});

La primera línea llama a express y la asigna, la segunda línea reasigna a app y así, tenemos el objeto de express para llamar listen en nuestra cuarta línea y aqui, le pasamos los parámetros para que inicie el servidor.

Vamos a ejecutar el comando node index.js y LISTO!!!, tenemos nuestro primer servidor, el cual, ya es accesible desde localhost:3000 pero, al abrir esto en nuestro navegador nos muestra un error, ¿qué pasó?.

Bueno, en este caso hemos iniciado un servidor pero Express no tiene ninguna declaración, es decir, ninguna ruta por lo que no sabe a dónde ir. Vamos a agregar la siguiente línea arriba de app.listen(...) :

app.get('/', function (req, res) {
  res.send('Mensaje desde express');
});

Detenemos nuestro servidor con CTRL+C y después lo volvemos a iniciar con node index.js , actualizamos la página en el navegador y, Listo!!!, tenemos una página de inicio que nos muestra Mensaje desde express.

¿Qué pasó aquí?, bueno, con ```.get()`` le dimos que la ruta raíz / será la que reciba de entrada nuestras peticiones por el método GET.

Veamos rápido los métodos:

GET es el método que permite obtener un recurso desde la URL. Es decir, si yo tengo http://localhost:3000/hola el recurso solicitado es /hola si en express modificamos el primer parámetro por /hola y vamos a la dirección previamente mencionada veremos el saludo, pero si vamos a la raíz de nuevo, veremos el mismo error de hace un momento.

POST es un método que permite el envío de información del cliente hacia nuestro servidor, y puede combinarse (por así decirlo) con una parte de GET ya que, POST también puede saber la URL en la cual estará recibiendo este método. Si nosotros cambiamos .get(…) por .post(…) y vamos a la misma URL de /hola veremos un error, pero, si hacemos uso de una herramienta tercera y le mandamos un POST (como ARC) veremos “Mensaje desde express”:

curl http//localhost:3000/hola

Ahora, si duplicamos el código y lo ponemos en ambos casos, con GET y POST y visitamos el link, podemos ver que funcionan ambos casos, pero modifiquemos un poco el código quedando algo como esto:

const express = require("express");
const app = express();app.post('/hola', function (req, res) {
  res.send('[POST]Saludos desde express');
});app.get('/hola', function (req, res) {
  res.send('[GET]Saludos desde express');
});app.listen(3000, () => {
 console.log("El servidor está desde en el puerto 3000");
});

Y como sabemos, necesitamos reiniciar nuestro servidor cada vez que hagamos cambios, esto se puede evitar con Nodemon

Si visitamos http://localhost:3000/hola veremos [GET]Saludos desde express y si le mandamos un POST a la misma dirección veremos [POST]Saludos desde express

Así es como manejamos, GET y POST. A su vez como mencioné previamente está PUT, este método es idéntico a POST y DELETE es idéntico a GET.

¿Pero en qué se diferencian?, vamos a hacerlo de la siguiente forma:

  • GET = Obtener
  • POST = Crear
  • PUT = Actualizar
  • DELETE = Eliminar

Entonces, entendiendo esto, podemos reutilizar la misma URL con distintos métodos, por ejemplo pensando que tenemos una libreta de direcciones podemos usar la URL /usuario para obtener un usuario en GET, POST para crearlo, PUT para actualizarlo y DELETE Para eliminarlo.

Vamos a crear un objeto global entonces aprovechando esta idea, con la siguiente información:

let usuario = {
 nombre:'',
 apellido: ''
};

Y modificaremos el código base para tener las 4 opciones disponibles, GET, POST, PUT, DELETE con su respectiva dirección en /usuario plus, dos direcciones, una para el error 404 de una ruta no encontrada y, una para la raíz / .

Por último agregaremos una variable de datos que nos permitirá enviar la respuesta del servidor al cliente que nos consulta esa información.

Voy a poner primero todo el código y seguiremos por partes, se necesita una dependencia adicional para el manejo de datos en la recepción “es decir, manejar más fácil los datos de POST a nuestro servidor”, para ello instalamos con:

npm install body-parser --save

Una vez hecho esto ahora sí, al código:

const express = require("express");
const bodyParser = require('body-parser');
const app = express();app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());let usuario = {
 nombre:'',
 apellido: ''
};let respuesta = {
 error: false,
 codigo: 200,
 mensaje: ''
};app.get('/', function(req, res) {
 respuesta = {
  error: true,
  codigo: 200,
  mensaje: 'Punto de inicio'
 };
 res.send(respuesta);
});app.get('/usuario', function (req, res) {
 respuesta = {
  error: false,
  codigo: 200,
  mensaje: ''
 };
 if(usuario.nombre === '' || usuario.apellido === '') {
  respuesta = {
   error: true,
   codigo: 501,
   mensaje: 'El usuario no ha sido creado'
  };
 } else {
  respuesta = {
   error: false,
   codigo: 200,
   mensaje: 'respuesta del usuario',
   respuesta: usuario
  };
 }
 res.send(respuesta);
});app.post('/usuario', function (req, res) {
 if(!req.body.nombre || !req.body.apellido) {
  respuesta = {
   error: true,
   codigo: 502,
   mensaje: 'El campo nombre y apellido son requeridos'
  };
 } else {
  if(usuario.nombre !== '' || usuario.apellido !== '') {
   respuesta = {
    error: true,
    codigo: 503,
    mensaje: 'El usuario ya fue creado previamente'
   };
  } else {
   usuario = {
    nombre: req.body.nombre,
    apellido: req.body.apellido
   };
   respuesta = {
    error: false,
    codigo: 200,
    mensaje: 'Usuario creado',
    respuesta: usuario
   };
  }
 }
 
 res.send(respuesta);
});app.put('/usuario', function (req, res) {
 if(!req.body.nombre || !req.body.apellido) {
  respuesta = {
   error: true,
   codigo: 502,
   mensaje: 'El campo nombre y apellido son requeridos'
  };
 } else {
  if(usuario.nombre === '' || usuario.apellido === '') {
   respuesta = {
    error: true,
    codigo: 501,
    mensaje: 'El usuario no ha sido creado'
   };
  } else {
   usuario = {
    nombre: req.body.nombre,
    apellido: req.body.apellido
   };
   respuesta = {
    error: false,
    codigo: 200,
    mensaje: 'Usuario actualizado',
    respuesta: usuario
   };
  }
 }
 
 res.send(respuesta);
});app.delete('/usuario', function (req, res) {
 if(usuario.nombre === '' || usuario.apellido === '') {
  respuesta = {
   error: true,
   codigo: 501,
   mensaje: 'El usuario no ha sido creado'
  };
 } else {
  respuesta = {
   error: false,
   codigo: 200,
   mensaje: 'Usuario eliminado'
  };
  usuario = { 
   nombre: '', 
   apellido: '' 
  };
 }
 res.send(respuesta);
});app.use(function(req, res, next) {
 respuesta = {
  error: true, 
  codigo: 404, 
  mensaje: 'URL no encontrada'
 };
 res.status(404).send(respuesta);
});app.listen(3000, () => {
 console.log("El servidor está inicializado en el puerto 3000");
});

Lo primero, nuevamente, es cargar express, pero ahora tambièn se carga el body-parser e inicializar express en nuestra constante app . Posterior, gracias a body-parser podremos manejar los datos en formato JSON de la recepción en POST/PUT desde el cliente, es decir, que, cuando el cliente haga una petición, indicará la cabecera Content-Type: application/json y nuestra API va a servir esta petición ejecutando lo que el cliente necesita.

Después, creamos la variable usuario para tener sus propiedades previamente asignadas de forma global, así como una variable llamada respuestaque nos permitirá enviar una respuesta hacia el cliente.

Posterior creamos una ruta raíz / que nos permitirá poder mostrar una base de nuestra API.

Por último el caso del error 404 que previamente comentaba.

Y ahora sí, nuestro primer método, en GET vamos a revisar, ¿el cliente ya se creó?, si no se ha creado, entonces asignamos el error a nuestra variable de respuesta, en otro caso, mandamos el usuario en la respuesta y le indicamos al cliente que todo bien.

curl http//localhost:3000/usuario

Después en POST revisamos si, el cuerpo del POST incluye el nombre y el apellido, si no lo incluye, mostraremos un error, si lo incluye pero el usuario no está vacío, mostramos un error pero si está vacío e incluye los parámetros solicitados, entonces lo creamos y le respondemos al cliente con la información.

Siguiente en PUT vamos a recibir la solicitud, seguimos la misma lógica que en POST pero, si en este caso, está vacío el nombre o el apellido significa que no ha sido creado el usuario, por lo tanto no hay nada que actualizar, sin embargo, si no está vacío y recibimos ambos parámetros, entonces, actualizamos al usuario.

Por último tenemos el DELETE que eliminará al usuario.

Ahora, vamos a modificar y simplificar un poco nuestro código usando app.route() de express, que nos permite agrupar la misma URL que responderá a distintos métodos ya que los vimos por separado y dejaremos este post hasta aquí.

const express = require("express");
const bodyParser = require('body-parser');
const app = express();app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());let usuario = {
 nombre:'',
 apellido: ''
};let respuesta = {
 error: false,
 codigo: 200,
 mensaje: ''
};app.get('/', function(req, res) {
 respuesta = {
  error: true,
  codigo: 200,
  mensaje: 'Punto de inicio'
 };
 res.send(respuesta);
});app.route('/usuario')
 .get(function (req, res) {
  respuesta = {
   error: false,
   codigo: 200,
   mensaje: ''
  };
  if(usuario.nombre === '' || usuario.apellido === '') {
   respuesta = {
    error: true,
    codigo: 501,
    mensaje: 'El usuario no ha sido creado'
   };
  } else {
   respuesta = {
    error: false,
    codigo: 200,
    mensaje: 'respuesta del usuario',
    respuesta: usuario
   };
  }
  res.send(respuesta);
 })
 .post(function (req, res) {
  if(!req.body.nombre || !req.body.apellido) {
   respuesta = {
    error: true,
    codigo: 502,
    mensaje: 'El campo nombre y apellido son requeridos'
   };
  } else {
   if(usuario.nombre !== '' || usuario.apellido !== '') {
    respuesta = {
     error: true,
     codigo: 503,
     mensaje: 'El usuario ya fue creado previamente'
    };
   } else {
    usuario = {
     nombre: req.body.nombre,
     apellido: req.body.apellido
    };
    respuesta = {
     error: false,
     codigo: 200,
     mensaje: 'Usuario creado',
     respuesta: usuario
    };
   }
  }
  
  res.send(respuesta);
 })
 .put(function (req, res) {
  if(!req.body.nombre || !req.body.apellido) {
   respuesta = {
    error: true,
    codigo: 502,
    mensaje: 'El campo nombre y apellido son requeridos'
   };
  } else {
   if(usuario.nombre === '' || usuario.apellido === '') {
    respuesta = {
     error: true,
     codigo: 501,
     mensaje: 'El usuario no ha sido creado'
    };
   } else {
    usuario = {
     nombre: req.body.nombre,
     apellido: req.body.apellido
    };
    respuesta = {
     error: false,
     codigo: 200,
     mensaje: 'Usuario actualizado',
     respuesta: usuario
    };
   }
  }
  
  res.send(respuesta);
 })
 .delete(function (req, res) {
  if(usuario.nombre === '' || usuario.apellido === '') {
   respuesta = {
    error: true,
    codigo: 501,
    mensaje: 'El usuario no ha sido creado'
   };
  } else {
   respuesta = {
    error: false,
    codigo: 200,
    mensaje: 'Usuario eliminado'
   };
   usuario = { 
    nombre: '', 
    apellido: '' 
   };
  }
  res.send(respuesta);
 });app.use(function(req, res, next) {
 respuesta = {
  error: true, 
  codigo: 404, 
  mensaje: 'URL no encontrada'
 };
 res.status(404).send(respuesta);
});app.listen(3000, () => {
 console.log("El servidor está inicializado en el puerto 3000");
});

De esta forma agrupamos la URL /usuario y ya podemos utilizar sus métodos ya que por ejemplo, pensemos que la _URL /usuario no debería poder eliminar usuarios, borramos el .delete() de estos y su contenido y listo, el DELETE queda desactivado de esta URL y así, si hacemos un módulo por ejemplo, podemos exportar estas rutas y hacer nuestro código más sencillo.

¿Qué se puede mejorar en este código?, que detecte si el tipo de contenido no sea application/json nos rechace, una forma más sencilla de setear la respuesta con una función, meter un servicio de autorización, y mas soluciones adicionales

En conclusión un API REST es una interfaz donde se conectan las aplicaciones para obtener, crear, actualizar o eliminar datos de forma sencilla, teniendo la opcion como clientes, o como proveedores del servicio permitir a otros realizar estas acciones gracias a los distintos métodos básicos o principales de HTTP (POST, GET, PUT, DELETE).

Se puede reutilizar la misma dirección para hacer distintas acciones.

GET sirve para obtener, POST para crear, PUT para actualizar y DELETE para eliminar.

Listo hasta el proximo post!!