Crear un API RESTFul con Node.js

Estudios para Agroforestación Inteligente y Transformación Digital de La Yeguada
26/06/2020
Propuesta para la Reactivación estratégica de la Región Central.
04/08/2020

Crear un API RESTFul con Node.js

Crear un RESTFul API con Node.js:

Creado por: Ing. Ricardo González

En el artículo anterior “Introducción a las Interfaces de Software a Software” evocamos los conceptos generales para establecer la comunicación entre dos sistemas para el intercambio de información. En el presente artículo vamos a crear un RESTFul API utilizando la plataforma Node.js (https://nodejs.org/), sin utilizar framework. Esta plataforma fue creada en el 2009 y es utilizada para el desarrollo de aplicaciones web escalables que permite ejecutar código JavaScript en el Servidor.

Puedes encontrar el codigo aqui: simple_api

Requerimientos:

  • Conocimiento básico de programación
  • JavaScript ES6 (const, let, Asignación desestructurante)
  • Tener instalado Node.js ≥ 10.0.0 (Mac/Windows/Linux)
  • Conocimiento en Node.js
  • Nodemon 2.0.4 (Se instalara dentro del tutorial)
  • Conocimiento de la Terminal (Mac/Linux) o CMD (Windows).

¡Listo!  Después de una muy breve introducción y describir los requerimientos podemos comenzar…

Lo primero es crear nuestro directorio, para esto abrimos la terminal y escribimos los siguientes comandos:

mkdir simple_api (mkdir: crea el directorio)

cd simple_api (cd: nos lleva al directorio creado)

npm init --y (esto crearà nuestro package.json)

Creamos un archivo con el nombre server.js, el cual va a contener la configuración básica para establecer la comunicación con el servidor web. De esta manera, el servidor estará preparado para aceptar peticiones y responder a las mismas. Por ahora solo emitirá el clásico mensaje “Hola Mundo”.

const http = require('http'); 
const port = 8080; 

const server = http.createServer((req, res) => res.end(‘Hola Mundo’)); 

server.listen(port, () => { 
console.log(`Server is running on http://localhost:${port}`); 
});

Para iniciar el servidor vamos a la terminal o CMD y colocamos este comando:

node ./server.js

Para ver nuestro “Hola Mundo” podemos escribir la dirección http://localhost:8080 en nuestro navegador de preferencia.  Una vez hecho esto, el mensaje aparecerá en nuestro buscador como se muestra en la siguiente imagen.

Luego, para evitar reiniciar nuestro servidor manualmente vamos a instalar Nodemon. El, tendrá la tarea de vigilar nuestro proyecto y reiniciar el servidor, al momento de detectar cualquier cambio. Esto nos dará velocidad en el desarrollo del API. Entonces, instalémoslo:

npm i --save-dev nodemon

Para completar la configuración se debe elimar la línea main en nuestro package.json dentro del directorio del proyecto y en la línea scripts ingresamos el comando start y como valor le asignamos el comando nodemon ./server.js

Listo, ya Nodemon se encargará de mantener los cambios realizados en el servidor.

Eliminar:

"main": "index.js",

Agregar:

"scripts": {

"start": "nodemon ./server.js",

"test": "echo \"Error: no test specified\" && exit 1"

},

Si, quieres saber mas de Nodemon este el sitio oficial nodemon.io

Ahora en nuestro proyecto (simple_api) vamos a crear un script con el nombre api.js y también creamos un arreglo de objetos JS con tres elementos como se muestra a continuación:

let contacts = [
    {
        id: 1,
        name: "Ricardo González",
        email: "ragj@mail.com"
    },
    {
        id: 2,
        name: "Pedro Pan",
        email: "ppan@mail.com"
    },
    {
        id: 3,
        name: "Logan Mendoza",
        email: "lm@mymail.com"
    }
]


A continuación, vamos a crear nuestra primera función para manejar las peticiones con el método POST:

exports.post = (req, res) => {
    let contact = '';

    req.setEncoding('utf8');
    req.on('data', (data) => {
        try {
            console.log('Grabando Datos...')
            contact += data; 
        } catch (error) {
            res.statusCode = 400;
            res.end(error);
        }
    });

    req.on('end', () => {
        try {
            contacts.push(JSON.parse(contact));
            console.log('Datos Grabados exitosamente!');
            res.end();
        } catch (error) {
            res.statusCode = 400;
            res.write('Bad request: la entrada debe ser en formato JSON\n')
            res.end();
        }       
    });
}

En la función POST vamos a concatenar la data en la variable contact dentro el evento data. Luego, en el evento end ingresaremos la data dentro del arreglo contacts como un Objeto JavaScript utilizando JSON.parse(contact).

Ahora vamos a crear la función que se encargara de las peticiones bajo el método GET:

exports.get = (res) => {
    res.statusCode = 200;
    let body = JSON.stringify(contacts) + '\n';
    res.setHeader('Content-Length', Buffer.byteLength(body));
    res.setHeader('Content-Type', 'application/json');
    res.end(`${body}`);
}

En esta función convertimos nuestro arreglo a formato JSON para enviarlo como respuestas a la petición. Establecemos los headers con información del contenido de la respuesta. En este caso, enviaremos el largo del contenido Content-Length y el tipo de contenido Content-Type en donde el contenido de la respuesta será enviado en formato JSON.

A continuación, procedemos a crear la siguiente función que tendrá la tarea de eliminar datos dentro del arreglo según las peticiones por id bajo el método DELETE:

exports.deleteMe = (req, res) => {
    const path = url.parse(req.url).pathname;
    const id = parseInt(path.slice(1), 10);

    const index = contacts.findIndex( c => c.id === id);

    if (isNaN(id)) {
        res.statusCode = 400;
        res.end('el Id debe ser un número\n');
    }
    if (index === -1) {
        res.statusCode = 400;
        res.end('id no encontrado\n');
    } else {
        res.statusCode = 200;
        contacts.splice(index, 1);
        res.end('Elemento borrado\n');
    } 
}

Dentro de la función deleteMe vamos a manipular el objeto req.url, utilizando el módulo nativo url de Node.js, el cual, proporciona el método parse. Este último convertirá el url en un objeto JavaScript para asi obtener el valor dentro la propiedad pathname y extraer el id de su valor. Una vez tengamos el id lo usaremos para encontrar el elemento a eliminar y para eliminar el registro en nuestro arreglo contacts.

Con el index del elemento nos aseguramos de que exista dentro del arreglo, en caso contrario enviamos “id no encontrado”. Si el elemento existe, utilizaremos el método splice para eliminarlo y finalizamos nuestra respuesta con el mensaje “Elemento borrado”.

Nuestro último método para este tutorial será la función putMe y tendrá como responsabilidad modificar los datos dentro del arreglo contacts bajo las peticiones PUT:

exports.putMe = (req, res) => {
    
    const path = url.parse(req.url).pathname;
    const id = parseInt(path.slice(1), 10);

    const index = contacts.findIndex( c => c.id === id);
    
    if (isNaN(id)) {
        res.statusCode = 400;
        res.end('El ID debe ser un número\n');
    }
    if (index === -1) {
        res.statusCode = 400;
        res.end('ID no encontrado\n');
    } else {
        let contact = '';
        let newContacts;
        res.statusCode = 200;
        req.setEncoding('utf8');

        req.on('data', (data) => {
            try {
                contact += data;
            } catch (error) {
                res.statusCode = 400;
                res.end(error);
            }
        });

        req.on('end', () => {
            try {
                newContacts = JSON.parse(contact);
                contacts[index].name = newContacts.name;
                contacts[index].email = newContacts.email;

                res.end('Registro actualizado correctamente\n');
            } catch (error) {
                res.statusCode = 400;
                res.write('Bad request: la entrada debe ser en formato JSON\n')
                res.end();
            }
            
        });
    }
}

En esta función manipularemos el objeto req.url, tal cual, como lo hicimos en nuestra función anterior. De igual forma nos aseguramos que exista el elemento dentro del arreglo contacts.

Para este caso, vamos a crear dos variables una inicializada con cadena de texto vacía y la otra sin inicializar. En la variable contact vamos a concatenar, como lo hicimos en la función POST, utilizando el evento data y dentro del evento end inicializamos newContact como un arreglo de objeto, convirtiendo contact en un objeto javaScript. Posteriormente, actualizamos el elemento dentro del arreglo contacts. Para esto, accedemos al elemento correcto utilizando el index dentro de la notación de corchete contacts[índiceDelElemento], y actualizamos el objeto accediendo a la propiedad a través de la notación del punto contacts[index].nombrePropiedad. Finalizamos nuestra respuesta con el mensaje ‘Registro actualizado correctamente’.

Listo, ya hicimos nuestros métodos para que nuestro servidor web se comporte como un RESTFul básico. Vamos a importar nuestras funciones a nuestro script server.js utilizando el método require() y desestructuramos los métodos. Ahora vamos a cambiar un poco el código para probar nuestras funciones.

const http = require('http');
const port = 8080;
const { post, get, deleteMe, putMe } = require('./api');

const server = http.createServer((req, res) => {
    switch (req.method) {
        case 'POST':
            post(req, res);
            return;
        case 'GET':
            get(res);
            return;
        case 'DELETE':
            deleteMe(req, res);
            return;
        case 'PUT':
            putMe(req, res);
            return;
        default:
            break;
    }
    
});

server.listen(port, () => {
    console.log(`Server is running on http://localhost:${port}`);
    
});

¡Bien!, ya nuestro servidor está listo para probrar nuestros métodos. Para interactuar con el api restful, que acabamos de hacer puedes hacerlo con curl o postman:

Utilizando CURL:

GET:

curl http://localhost:8080

 

POST:

curl -d '{"id":4,"name":"Mario Baracus","email":"mb@myemail.com"}' http://localhost:8080

 

PUT:

curl -X "PUT"  -d '{"name":"Alberto Chang","email":"ac@mayemail"}' http://localhost:8080/3

 

DELETE:

curl -X "DELETE" http://localhost:8080/4

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *