Saltar al contenido principal
Tema

Introducción a fastify

6 minutos de lectura

Índice

Fastify es un framework para NodeJS donde su mayor característica es su rapidez, también es de poca carga, tiene más de 20 mil estrellas en github y es casi 4 veces más rápido que express.

Explicaremos como hacer un crud de tareas y conectarlo a mongodb usando esta tecnología.

Instalación

Para instalarlo debemos ejecutar el siguiente comando en la terminal de nuestro proyecto.

Con npm:

$ npm install fastify

Con yarn:

$ yarn add fastify

Luego crearemos una carpeta src y dentro un archivo index.js, aquí es donde estará el código de nuestro backend.

Crear un servidor

Luego de instalarlo debemos importarlo y ejecutarlo, luego lo ponemos en escucha y lo probamos con una ruta.

1// Importamos fastify
2const app = require('fastify')({ logger: true });
3
4// Colocamos una ruta
5app.get('/', (req, res) => {
6 res.send("Hello World")
7})
8
9// Colocamos el puerto para el servidor
10const port = process.env.PORT || 3000
11
12// Ponemos en escucha el servidor
13app
14 .listen(port)
15 // Nos mostrara en consola la dirección en la cual está escuchando nuestro servidor
16 .then((adress) => console.log(`Server listening at ${adress}`))
17 .catch((error) => {
18 app.log.error(error);
19 process.exit(1);
20 });

Luego podemos iniciar el servidor con el siguiente comando en la terminal

$ node src/index

Y podremos ver que el servidor se ha iniciado en la dirección http://127.0.0.1:3000, si realizamos una petición GET a esa dirección tendremos como resultado el string de "Hello world".

Instalar Nodemon

En caso que hagamos un cambio en el código tendremos que volver a ejecutar el comando para iniciar el servidor, pero existe nodemon que nos soluciona este problema.

Para instalarlo debemos ejecutar el siguiente comando en nuestro proyecto.

Con npm:

$ npm install nodemon --save-dev

Con yarn:

$ yarn add --dev nodemon

Y añadimos los siguientes scripts en nuestro archivo package.json

1"scripts": {
2 "start": "node src/index",
3 "dev": "nodemon src/index"
4}

De esta manera usamos el comando npm run dev y cada cambio que se realice en el código se actualizara sin necesidad de volver a ejecutarlo.

Conectarlo a mongodb con mongoose

En nuestro caso para hacer una conexión con mongodb usaremos mongoose que nos facilita gran parte del trabajo y dotenv para proteger nuestras claves con variables de entorno.

Para instalarlos debemos ejecutar el siguiente comando en nuestro proyecto.

Con npm:

$ npm install mongoose dotenv

Con yarn:

$ yarn add fastify dotenv

Crearemos un archivo .env en la raíz de nuestro proyecto y allí colocaremos nuestra uri de mongodb.

1MONGODB_URI={Nuestra uri de mongodb}

También creamos un archivo .gitignore para que node_modules y nuestro archivo con las variables de entorno no se guarden en git.

1node_modules
2.env

Crearemos otro archivo llamado mongo.js para conectar la base de datos y haremos lo siguiente

1// Importamos connect de mongoose
2const { connect } = require('mongoose');
3
4// Importamos dotenv para habilitar las variables de entorno
5require('dotenv').config();
6
7// Colocaremos esta configuración
8const options = {
9 useNewUrlParser: true,
10 useUnifiedTopology: true,
11 useFindAndModify: false,
12 useCreateIndex: true,
13};
14
15// Y realizamos la conexión
16connect(process.env.MONGODB_URI, options)
17 // Si la conexión es exitosa se nos mostrará en
18 // consola el mensaje de 'Database connected'
19 .then(() => console.log('Database connected'))
20 // En caso contrario nos mostrara en consola un error
21 .catch((error) => console.error(error));

Luego este archivo podemos importarlo colocando require('./mongo') en nuestro archivo de index.js.

Rutas

Podemos modularizar nuestras rutas y tener mucho más ordenado el código haciéndolo de esta manera.

1// Nos da los parámetros de app, options y el done.
2const tasks = (app, options, done) => {
3
4 // Y podremos añadir las rutas que queramos
5 app.get('/tasks', (req, res) => {
6 res.send('Hello World')
7 })
8
9 // Debemos ponerlo para declarar el fin de las diferentes rutas
10 done()
11}
12
13module.exports = tasks

Este código lo dejaremos en un archivo para luego registrarlo, en este caso en una nueva carpeta routes y un archivo llamado tasks.js.

Para importar y registrar las rutas lo haremos de la siguiente manera en nuestro archivo index.js.

1app.register(require('./routes/tasks'))

Añadir esquemas con mongoose

Para definir la estructura de los documentos podemos usar los esquemas de mongoose, estos los tendremos en una carpeta models y cada uno tendrá su archivo propio.

1// Importamos Schema y model de mongoose
2const { Schema, model } = require('mongoose')
3
4// Creamos el esquema que definirá la estructura de cada tarea
5const taskSchema = new Schema({
6 // Este será el contenido de cada tarea, el cual debe ser tipo string
7 // y ser necesario para la creación de una tarea
8 content: {
9 type: 'string',
10 required: true,
11 },
12 // Boleano que indicará si la tarea en cuestión se ha completado o no
13 done: Boolean,
14})
15
16// Creamos el modelo y lo exportamos
17const Task = model('task', taskSchema)
18
19module.exports = Task

Controladores y crear el crud

Los controladores que pasaremos a cada ruta los añadiremos en una carpeta controllers y en un archivo llamado tasks.js. También importaremos el esquema que usaremos repetidas veces.

1const Task = require('../models/task');
2
3const getTasks = (req, res) => {
4 res.send('Hello World')
5}
6
7module.exports = { getTasks }

Y los importamos en nuestro archivo de rutas.

1const { getTasks } = require('../controllers/tasks')
2
3const tasks = (app, options, done) => {
4 app.get('/tasks', getTasks)
5
6 done()
7}
8
9module.exports = tasks

Luego de hacer todo esto ya tenemos todo listo para crear el crud.

Obtener todas las tareas

Usaremos el método find para obtener todos los documentos que tengan el esquema que definimos.

1const getTasks = (req, res) => {
2 Task.find()
3 // Si la operación fue exitosa, nos manda
4 // como respuesta todas las tareas
5 .then((results) => res.send(results))
6 // En su defecto nos muestra por consola el error
7 .catch((error) => console.error(error))
8}

Obtener una tarea por su identificador

Para esta ruta debemos usar el id que nos llega de los parámetros de la solicitud.

1// Colocamos el parámetro de id en la ruta
2app.get('/tasks/:id', getTask);
1const getTask = (req, res) => {
2 // Obtenemos el id de los parámetros de la solicitud
3 const { id } = req.params;
4
5 // Aplicaremos el método findById, a este debemos pasarle el id
6 Task.findById(id)
7 .then((result) => {
8 // Revisamos si encontró el documento
9 result
10 // Si fue encontramos lo enviamos como respuesta
11 ? res.send(result)
12 // Si no fue encontrado enviamos un error 404
13 : res.code(404).send({
14 statusCode: 404,
15 error: 'Not Found',
16 message: 'Task not found with given id',
17 });
18 })
19 .catch((error) => {
20 console.error(error);
21
22 res.code(400).send({
23 statusCode: 400,
24 error: 'Bad request',
25 });
26 });
27}

Añadir una tarea

Para añadir una tarea en muy importante especificar el método POST en la ruta.

1app.post('/tasks', addTask)

Luego de hacer eso, podemos hacer nuestro controlador.

1const addTask = (req, res) => {
2 // Extraemos el contenido y si la tarea fue completada del cuerpo de la solicitud
3 const { content, done } = req.body
4
5 // Creamos un objeto con esa información
6 const newTask = { content, done }
7
8 // Dispondremos del método create para insertar una nueva tarea
9 // a la base de datos, debemos pasarle el objeto recién creado
10 Task.create(newTask)
11 // Si fue creado exitosamente mandamos una respuesta con el
12 // código 201 y el mensaje de creado
13 .then(() => {
14 res.code(201).send({
15 statusCode: 201,
16 message: 'Created',
17 })
18 })
19 .catch((error) => {
20 console.error(error)
21
22 res.code(400).send({
23 statusCode: 400,
24 error: 'Bad request',
25 })
26 })
27}

Eliminar tarea

El proceso será similar al de obtener una tarea con su id pero especificando los métodos para borrar.

En la ruta debemos usar el método delete.

1app.delete('/tasks/:id', deleteTask)

Emplearemos el método findByIdAndDelete, este buscará la tarea y si la encuentra la borrar y nos devolverá el documento de la tarea

1const deleteTask = (req, res) => {
2 const { id } = req.params
3
4 Task.findByIdAndDelete(id)
5 .then((result) =>
6 result
7 ? res.send({
8 statusCode: 200,
9 message: 'Deleted',
10 })
11 : res.code(404).send({
12 statusCode: 404,
13 error: 'Not Found',
14 message: 'Task not found',
15 })
16 )
17 .catch((error) => {
18 console.error(error)
19
20 res.code(400).send({
21 statusCode: 400,
22 error: 'Bad request',
23 })
24 })
25}

Editar tarea

Y como último editar, aquí tendremos que extraer el id de los parámetros como los datos que lleguen del cuerpo de la solicitud, usaremos el metodo PUT.

1app.put('/tasks/:id', editTask)
1const editTask = (req, res) => {
2 // Extraemos el id, el content y el done de la solicitud
3 const { id } = req.params
4 const { content, done } = req.body
5
6 // Creamos el objeto con los datos editados
7 const editedTask = { content, done }
8
9 // Le pasamos el id y el objeto con los nuevos datos
10 Task.findByIdAndUpdate(id, editedTask)
11 .then((result) => {
12 result
13 ? res.send({
14 statusCode: 200,
15 message: 'Edited',
16 })
17 : res.code(404).send({
18 statusCode: 404,
19 error: 'Not Found',
20 message: 'Task not found with given id',
21 })
22 })
23 .catch((error) => {
24 console.error(error)
25
26 res.code(400).send({
27 statusCode: 400,
28 error: 'Bad request',
29 })
30 })
31}

Establecer un error 404 modificado

Para añadir un error 404 debemos usar setNotFoundHandler y configurar la respuesta que queramos.

1app.setNotFoundHandler((req, res) => {
2 res.code(404).send({
3 statusCode: 404,
4 error: 'Not Found',
5 });
6});

Fin

Hemos llegado al final, con esto podemos hacer un crud conectado a mongodb con fastify, es un framework sencillo de usar y con gran cantidad de características.