En esta sección, nos enfocaremos en la configuración de las rutas en nuestra aplicación para dividirla en múltiples partes. Si bien puede ser adecuado para un inicio tener todas las consultas en el archivo index.js
, a medida que agregamos más rutas y funcionalidades a nuestra API, puede volverse difícil de mantener. Por lo tanto, en esta sección, veremos cómo separar nuestras rutas en diferentes archivos para mejorar la organización y escalabilidad de nuestra aplicación.
Si te perdiste la parte 3 de esta serie puedes ir aquí.
Lo que vamos a hacer es dividir toda la lógica de nuestra aplicación, es decir, todas las rutas en distintos archivos e importarlos.
Configuración de las rutas en la estructura del proyecto con Express y Node.js
Para importar todas estas rutas vamos a utilizar un módulo de Express que se llama Router. Para esto vamos a crear una carpeta nueva llamada routes
.
Aprovechando que estamos creando una estructura de múltiples archivos. Sería una buena idea separar nuestro código de los archivos que solo son necesarios para que funcione el proyecto.
Entonces lo que vamos a hacer a continuación es crear una carpeta que se va a llamar, src
esta carpeta la vamos a crear en la raíz de nuestra aplicación. Dentro de esta carpeta src
se va a colocar el código y de esta forma tenemos un poco más organizado nuestro proyecto.
Por el momento vamos a ir a la terminal o a la consola y vamos a cancelar la ejecución de nuestro proyecto presionando control + c
.
Ahora vamos a empezar a ordenar nuestro proyecto, primero vamos a mover la carpeta routes
dentro de src
. También vamos a mover el archivo index.js
dentro de la carpeta src
.
Con esto va a estar todo el código fuente de nuestra aplicación dentro de la carpeta src
. El resto son archivos que están relacionados con el funcionamiento de la base de datos o node.js.
Ahora viene una parte muy importante que es ordenar. Cómo veníamos importando algunos módulos para mantener funcionando la aplicación, ahora tendremos que mover esas importaciones.
Por ejemplo, en index.js
estamos importando Express y el archivo db.js
, esto sigue igual, ya que no sufre ninguna modificación porque están al mismo nivel tanto el archivo index.js
como el de db.js
.
Sin embargo, si tomamos en cuenta el archivo package.json
le habíamos dicho a nodemon que ejecute el archivo index.js
. Por lo tanto, Node.js va a buscar el archivo index.js
en el root o raíz y ya no está ahí. Entonces vamos a tener que modificar el package.json
en la sección dev
, donde dice nodemon index.js
, tenemos que agregar src/ index.js
.
Habiendo hecho estas modificaciones deberíamos probar, para ver si no arroja ningún error. Para esto vamos a la consola y ejecutamos:
npm run dev
Organizando las rutas con Express Router en la configuración de las rutas
Ahora es momento de dividir nuestra lógica, es decir, vamos a organizar las rutas. Primero vamos a ir a la carpeta routes
y vamos a crear dos archivos, el primer archivo, se va a llamar employees.routes.js
y el otro index.routes.js
. Lo vamos a hacer de esta forma para luego reconocer cuándo vamos a estar refiriéndonos a unas rutas, o controladores u otro tipo de archivos. (A veces no es necesario colocar routes.js, también funcionaría employees.js).
En este archivo employees.routes.js
recién creado, vamos a importar Express, pero ya no vamos a traer toda la biblioteca de Express, sino que vamos a traer tan solo una función de Express que se llama Router.
const express = require('express')
Un Router en Express nos ayuda a estructurar nuestra aplicación en diferentes módulos, cada uno encargado de manejar un conjunto de rutas específicas. Esto facilita el desarrollo, la organización y el mantenimiento de nuestra aplicación.
const router = express.Router()
module.exports = router
Finalmente vamos a exportarlo. Esta porción de código básicamente lo que hace es decirle a Express que tenga un grupo de rutas.
Configuración de las rutas utilizando el enrutador de Express en index.js y employees.routes.js
Vamos a ir al archivo index.js, seleccionamos todas las rutas que tenemos en ese archivo que son las siguientes:
app.get('/employees', (req, res) => res.send('obteniendo empleados'))
app.post('/employees', (req, res) => res.send('agregando empleados'))
app.put('/employees', (req, res) => res.send('actualizando empleados'))
app.delete('/employees', (req, res) => res.send('eliminando empleados'))
Y las movemos justo después del enrutador, es decir, después de la variable router
en el archivo employees.routes.js
.
Ahora tenemos que tener en cuenta que en este archivo, app
no existe, pero existe router que vendría a ser un equivalente. Básicamente, viene siendo lo mismo, de hecho router también tiene sus métodos GET
, POST
, PUT
y DELETE
.
Entonces en lugar de utilizar app
vamos a utilizar router
.
const router = express.Router()
router.get('/employees', (req, res) => res.send('obteniendo empleados'))
router.post('/employees', (req, res) => res.send('agregando empleados'))
router.put('/employees', (req, res) => res.send('actualizando empleados'))
router.delete('/employees', (req, res) => res.send('eliminando empleados'))
module.exports = router
Ahora, para poder añadir todas estas rutas, tenemos que importar router y para esto vamos a ir al archivo index.js y escribimos lo siguiente:
const employeesRoutes = require("./routes/employees.routes.js")
Acá estamos requiriendo el archivo, employees.routes.js
colocándolo justo antes del app.listen(3000)
en index.js
.
Para utilizarlo vamos a decir app.use()
y el nombre de la constante que le pusimos en este caso es employeesRoutes
quedando de la siguiente manera:
app.use(employeesRoutes)
app.listen(3000)
Con esto ya tendríamos las rutas nuevamente, Si guardamos tendría que funcionar de la misma manera como estaba funcionando hasta ahora.
Para comprobar esto podemos ir a la extensión Thunder client, y comprobar las rutas que habíamos probado anteriormente con los verbos GET
, POST
, PUT
y DELETE
.
Configuración de la ruta /ping y conexión a la base de datos en index.routes.js
A partir de aquí vamos a probar la ruta /ping, Para esto vamos a crear otro archivo llamado index.routes.js
, dentro de la carpeta routes
, lo mismo vamos a importar Express y vamos a importar router
, igualmente vamos a crear un enrutador a partir de router, para finalmente exportarlo.
const express = require('express')
const router = express.Router()
router.get('/ping', async (req, res) => {
try {
const result = await query('SELECT "pong" AS resultado');
res.json(result[0].resultado);
} catch (error) {
console.error(error);
res.status(500).send('Error al obtener la información');
}
});module.exports = router
Pero si nosotros guardamos en este momento, nos va a marcar un error porque no tenemos la conexión a nuestra base de datos. Ya que para usar el metodo query()
lo tenemos que importar junto con pool
recordando que pool tienen la conexión a la base de datos.
Para esto vamos a ir a nuestro index.js
y cortar la siguiente línea
const pool = require('./db.js')
Y la vamos a pegar en index.router.js
const pool = require('../db.js')
Si nosotros pegáramos, así nada más no funcionaría, porque el archivo index.routes.js
estaría buscando la misma carpeta al archivo db.js
y no está ahí, hay que subir un nivel utilizando la sintaxis ../
para que encuentre el archivo db.js
.
Cómo utilizar el módulo util() para soportar promesas en la configuración de las rutas
Además, recordamos que para que funcionen las promesas tenemos que utilizar el módulo util()
como a continuación se explica:
El módulo mysql
, no soporta promesas de forma nativa, para esto se utiliza el paquete util
de Node.js para convertir las funciones de devolución de llamada (callbacks) en promesas.
Para hacer esto, primero se debe importar el módulo util
de Node.js:
const util = require('util');
Luego, se utiliza la función util.promisify()
para convertir la función de devolución de llamada en una función que devuelve una promesa. Por ejemplo, para convertir la función pool.query()
en una función que devuelve una promesa se puede hacer lo siguiente:
const query = util.promisify(pool.query).bind(pool);
De esta forma, la función query()
devolverá una promesa en lugar de aceptar una función de devolución de llamada. Se puede utilizar la función query()
de la misma manera que la función pool.query()
original, pero en lugar de proporcionar una función de devolución de llamada, se puede usar la sintaxis await
para esperar la resolución de la promesa.
Ahora, para index.routes.js
, vamos a importarlo desde la carpeta routes
al archivo index.routes.js
de la siguiente manera:
const indexRoutes = require("./routes/index.routes.js")
Guardamos index.js
y vamos a ver que todo funciona como antes.