
Desarrolla tu API REST en Node.js
Una de las cosas con las que más cómodo me siento es con la facilidad con la que, usando JavaScript y TypeScript, puedo desarrollar cualquier tipo de producto, desde el back hasta el front, pasando por dispositivos móviles o aplicaciones de Alexa. En esta entrada te comento, a nivel didáctico, distintos proyectos usados y librerías para aprender a montarte tu propio back-end para que consuman tu API REST.
Tu API REST
Cuando creamos una API REST tenemos muchas tecnologías y opciones para poder realizarla con éxito. Hay tantas que dependerá de la naturaleza del problema cuál debas elegir. Ya sea con TypeScript o JavaScript sobre Node.js, debes pensar cómo y de qué manera estructurar tu código. Ya uses MongoDB, Amazon, MariaDB o Firebase, hacerte tu propio back te va a dar el control de cómo y de qué manera acceden a tus recursos desde cualquier dispositivo.
En esta entrada te mostraré distintas tecnologías y proyectos usados como ejemplos con el alumnado o a nivel personal donde se integran distintas opciones. Algunas, ya verás, se irán repitiendo en ellos como un patrón base a seguir.

Principales ideas
Adapta a tu problema
Divídela por capas; usa, por ejemplo, el patrón MVC, que en Node.js ofrece una arquitectura de fácil implementación y extensión de tu problema. Rutas 100% RESTful, usa los verbos HTTP para realizar todas tus operaciones. Patrón de operaciones CRUD sobre recursos: podrás añadir, listar, modificar o eliminar. Sube tus ficheros a tu servidor. Todo almacenado usando MongoDB.

Seguridad ante todo
JSON Web Token (abreviado JWT) es un estándar abierto basado en JSON propuesto por IETF (RFC 7519) para la creación de tokens de acceso que permiten la propagación de identidad y privilegios. Además, hemos implementado la opción de refresco de tokens para añadir más funcionalidad.

CI/CD
Compila, prueba, despliega. Solo haz clic. Mejora tu productividad aplicando integración y despliegue continuo (CI/CD). Usaremos GitHub Actions para crear un flujo de trabajo y compilar, realizar el análisis de código estático y ejecutar pruebas automáticas para la detección temprana de errores y, finalmente, el despliegue de todo el proyecto en Heroku y DockerHub.
![]()
La nube es tu amiga
No importa dónde estés. Yo estaré allí. No te limites a implementar en un solo lugar: usa la nube para un desarrollo continuo y descentralizado. Usa MongoDB Atlas, Firebase, Amazon AWS, GitHub como repositorio de código, pruebas unitarias automatizadas, Heroku y DockerHub para su despliegue. Si no tienes cliente, puedes usar Postman. Todo esto ayudará a mejorar tu productividad. No importa dónde estés, simplemente desarrolla tu API para que esté siempre disponible.
![]()
NodeMonREST
Ejemplo de API REST en Node.js, usando Mongo, JWT y AWS S3 con CI/CD bajo GitHub Actions para fines docentes.
Descripción
Este proyecto tiene nombre de Pokemon 😃. El objetivo principal docente es aplicar distintas técnicas para construir un esqueleto de API REST usable en distintos proyectos. La idea es hacer un esqueleto lo suficientemente genérico, adaptable y extensible en módulos para ser aplicado en distintos problemas y con él resolver cuestiones que se nos pueden presentar genéricas en cada uno de ellos, con el objetivo de mostrar para el ámbito docente cómo poder realizarlo. Es una aplicación puramente docente. Entre las distintas técnicas usadas destacan:
- Distribución de los elementos del sistema. Tenemos distribuidos en distintos nodos cada uno de los componentes cruciales del sistema: código, información y almacenamiento de ficheros.
- Patrón MVC. La vista será cualquier cliente que consuma nuestra API.
- Asincronía y respuesta a eventos. Uso de promesas e interacción basada en eventos, que es uno de los aspectos más fuertes de Node.js.
- Acceso a bases de datos NoSQL usando MongoDB.
- Autenticación y autorización usando JWT.
- Autorización basada en permisos de usuario.
- Manejo de CORS.
- Algunos patrones de diseño conocidos.
- JS código ECMA2019. De esta manera nos aseguramos seguir los estándares marcados para este tipo de lenguaje, pero tratando los módulos como indica Node.js, usando Babel para compatibilidad. Además, se ha aplicado el estilo AirBnB, uno de los más seguidos con el objetivo de mantener una filosofía de sintaxis y estilo de programación ampliamente seguida en la comunidad JS/Node.
- Almacenamiento en la nube usando AWS.
- Desarrollo CI/CD usando GitHub Actions.

Tecnologías y librerías usadas
Atención
Este proyecto tiene algo de antigüedad y puede que las librerías estén en desuso. Te recomiendo que eches un ojo a TypeScript API REST porque, siguiendo esta misma filosofía, puedes ver una versión más moderna en el uso de librerías, organización de código y distintas versiones de persistencia de la información.
- Node.js. JS en servidor.
- MongoDB. He usado su versión en la nube Atlas.
- Express. Framework de aplicaciones web para la API. Con él creo y gestiono las rutas. Además, nos permite fácilmente crear middlewares, con lo cual podremos aplicar logs específicos, filtrar para autorizaciones y autenticaciones y ampliar mediante middleware. Es lo que más me gusta de esta librería. Te recomiendo mirar el código de los ficheros route y middleware para ver cómo realizo estas acciones. Una de las cosas importantes es cómo he creado el servidor para que pueda ser levantado como instancia en cada una de las pruebas.
- Mongoose. Conjunto de librerías para operar con bases de datos MongoDB. He implementado el acceso usando singleton.
- JWT-Simple. Para implementar la autenticación basada en JWT. Esta librería actúa en base a middleware con Express. Los propios tokens caducan dependiendo del valor de
.envTOKEN_LIFEen minutos. Para la parte de autorización, también hemos encapsulado en ellos los permisos de usuario que tengan. También hemos usado el refresco de tokens, en base a UUID almacenando los tokens de refresco en MongoDB con un índice TTL de la colección en base al valor de.envTOKEN_REFRESHen minutos. De esta manera se autodestruyen pasado ese tiempo y libera el token de refresco asociado al token de usuario, dando un poco de seguridad extra. El objetivo de implementar este tipo de token de refresco es que, si el access token tiene fecha de expiración, una vez que caduca el usuario tendría que autenticarse de nuevo para obtener un access token. Con el refresh token, este paso se puede saltar y con una petición a la API obtener un nuevo access token que permita al usuario seguir accediendo a los recursos de la aplicación hasta que el refresh token caduque. Se debe tener en cuenta que el TTL del token de autenticación debe ser menor que el de refresco. - BCrypt. Librería de criptografía para manejar las contraseñas de los usuarios.
- Body Parser. Middleware que parsea los body como objetos (ya no se utiliza, pero cuando hice este proyecto sí; puedes mirar el ejemplo con TypeScript siguiente para ver otras opciones).
- Cors. Middleware para manejo de CORS.
- Dotenv. Para leer las variables de entorno del fichero
.env. - Morgan. Middleware Request logger el cual nos permitirá sacar logs de nuestras peticiones HTTP.
- UUID. Implementa el RFC4122 UUID para los tokens de refresco.
- Express-fileupload. Es un middleware para Express el cual nos ayuda a procesar peticiones multipart o subida de imágenes. Se ha puesto que el tamaño máximo por imagen sea 2 MB, aunque se puede cambiar en el fichero
.env. Los directorios para almacenar imágenes o ficheros están en.env; puedes poner el mismo o lo que quieras, pues se crean dinámicamente dentro depublic/uploads(FILES_PATH) y son accesibles directamente por la rutaurl/files(FILES_URL). Puedes usar el mismo si quieres. - AWS. Se ha implementado el sistema de almacenamiento en la nube para no depender localmente del servidor. Si quieres la versión en el servidor, revisa esta rama. La idea de usar este tipo de tecnologías es aprender a usar almacenamiento en la nube siguiendo la filosofía de distribución de cada uno de los elementos del sistema: código, bases de datos y ficheros.
- Joi. Nos sirve para validar los datos de entrada en base a un esquema de validación, por si no usamos la validación en los propios esquemas de Mongo. Es importante que el back valide todos los datos por si se ha escapado algo del front. No podemos dejar nada a la suerte. ¡Luke, somos la última esperanza!
- Mongoose-unique-validator. Nos sirve para validar los campos unique. Actúa como middleware.
- Underscore. Nos permite extender las posibilidades de la programación funcional para algunos métodos.
- Express-handlebars. Personalmente, uno de los mejores motores de plantillas para Node.js, basado en Handlebars. Lo he usado de ejemplo para hacer algunas páginas estáticas de presentación de la API.
- Mocha y Chai. Se han utilizado estas librerías para los test por su funcionalidad y porque se adaptan perfectamente al proceso de integración continua que se ha marcado como objetivo.
- Babel y ESLint con el objetivo de construir un código ampliamente compatible y estandarizado de JS.
- GitHub Actions. Es una de las grandes herramientas que se ha usado para la integración/distribución continuas CI/CD. Para ello hemos integrado el entorno de ejecución con pruebas y el despliegue como docker en DockerHub y su despliegue para su uso en Heroku.
Repositorio
Notas-Back-NEM
Este proyecto tiene como objetivo hacer la parte de backend por capas de una aplicación de notas para consumirla con distintos clientes usando las tecnologías de Node.js, MongoDB y Express, y está basada en el proyecto NodeMonREST. Como implementación de almacenamiento se ha utilizado Google Firebase Cloud Storage.
Repositorio
Proyecto disponible:
TypeScript API REST
Ejemplo de una API REST realizada con TypeScript. Autenticación, CRUD, transferencia de ficheros. Modos de trabajo en: memoria, MongoDB o MariaDB. Despliegue en Docker y test con Jest.
Descripción
El proyecto consiste en que tengas un ejemplo de API REST, pero realizada con TypeScript, con el objetivo de mejorar con tipos tus desarrollos. Además, propone el uso de ficheros, autenticación y autorización mediante JWT. Tiene tres modos de uso: memoria, con MongoDB (NoSQL) y MariaDB (SQL). Acceso desde: http://localhost:8000.

Arquitectura y diseño
El diseño de esta API REST se corresponde con el patrón Servidor->Enrutador->Controlador->Modelo. El servidor escucha en un puerto diversas peticiones. Las procesa según su ruta o punto de entrada y se las pasa al enrutador. El enrutador analiza la petición dependiendo de la ruta y se la pasa al controlador correspondiente a dicha ruta, que ejecutará el método indicado. El controlador realiza el método indicado según la ruta, consultando los modelos y el almacenamiento para ello. El modelo es la estructuración de los datos a tratar.
En todo momento se ofrece información de la petición en base a los códigos de estado HTTP.
Modos de funcionamiento
Este proyecto está basado en dos modos de funcionamiento en la URL: http://localhost:8000.
- Memoria: usando almacenamiento en memoria. Lo tienes en la rama memoria.
- MongoDB: usando almacenamiento en MongoDB. Lo tienes en la rama MongoDB.
- MariaDB: usando almacenamiento en MariaDB. Lo tienes en la rama MariaDB.
Autenticación y autorización: JWT y middleware
Se ha implementado un sistema de autenticación y autorización basado en JWT y aplicando un middleware para analizar si el usuario puede entrar a un recurso, ya sea porque está autenticado para ello (auth), tiene permisos dependiendo de su rol (grant) o dicho recurso le pertenece si tenemos datos que los relacionan (owner). Se ha jugado con distintas políticas dependiendo del recurso y se puede adaptar a las distintas necesidades del problema. En el código podrás ver distintas soluciones con middleware o dentro del controlador.
Validadores de datos
Se han implementado dos sistemas de validación de campos según los requisitos de los tipos de datos. Por un lado, un middleware de validación y por otro, si no queremos hacerlo de esta manera, con funciones auxiliares en el propio controlador.
Endpoints
Los endpoints para conectarse y consumir esta API REST empiezan siempre por /api/vx/recurso, donde x es la versión de esta API y recurso es el recurso a consumir, por ejemplo /api/v1/juegos desde http://localhost:8000.
| Método | Recurso | Auten./Autor. | Descripción |
|---|---|---|---|
| POST | user/register | -- | Registra un usuario/a. |
| POST | user/login | -- | Se identifica en el sistema y obtiene token de acceso. |
| GET | /user/id | auth | Obtiene los datos del usuario/a con id indicado si pertenece a él/ella. |
| PUT | /user/id | auth | Modifica los datos del usuario/a con id indicado si pertenece a él/ella. |
| DELETE | /user/id | auth | Elimina el usuario/a con id indicado si pertenece a él/ella. |
| GET | /juegos | -- | Obtiene todos los juegos. |
| GET | /juegos/id | -- | Obtiene el juego con el id indicado. |
| POST | /juegos | auth | Añade el juego. |
| PUT | /juegos/id | auth, owner | Modifica el juego con el id indicado si pertenece al usuario/a. |
| DELETE | /juegos/id | auth | Elimina el juego con el id indicado si pertenece al usuario/a. |
| GET | /files | auth, grant('ADMIN') | Obtiene todos los ficheros. Solo Admin. |
| GET | /files/id | auth | Obtiene datos del fichero con el id indicado si pertenece al usuario/a. |
| GET | /files/download/id | -- | Descarga el fichero con el id indicado. |
| POST | /files | auth | Añade el fichero. |
| PUT | /files/id | auth | Modifica el fichero con el id indicado si pertenece al usuario/a. |
| DELETE | /files/id | auth | Elimina el fichero con el id indicado si pertenece al usuario/a. |
TDD: JEST
Se ha usado la librería Jest con TypeScript para realizar los test siguiendo un enfoque TDD y Supertest para testear las peticiones HTTP a la API.
