API REST con NodeJS, Express y MySQL
Ya vimos en una entrada pasada que era un API REST y como configurar un simple servidor tanto con HTTP como en Express. En esta ocasión veremos como conectar un servidor NodeJS+Exepress con una base de datos MySQL.
En primer lugar nos será necesario tener instalado en nuestro sistema MySQL (o MariaDB) y para mayor facilidad en su gestión es muy recomendable tener una herramienta como phpMyAdmin.
En este ejemplo vamos a crear un servicio que nos permita solicitar la carta de un restaurante, pudiendo ver de qué ítems consta, añadir nuevos platos o eliminarlos. Esto se traduce en un API REST con los métodos (o verbos) GET, POST y DELETE implementados.
Creando una base de datos de ejemplo
Vamos a crear primero una base de datos llamada nodedb en la que crearemos la tabla carta:
CREATE TABLE carta
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
plato VARCHAR(25) NOT NULL,
descripcion VARCHAR(255),
precio DECIMAL(12, 2) NOT NULL,
disponible BOOLEAN
)
Añadimos ahora un par de platos a nuestra base de datos:
Insert into Carta (plato, descripcion, precio, disponible) values ("Paella", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore", 9.99, true);
Insert into Carta (plato, descripcion, precio, disponible) values ("Entrecot", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore", 19.99, true);
Los métodos que vamos a implementar son tres de los cuatro típicos de un CRUD (create, read, update, delete):
Método | Url | Acción |
---|---|---|
GET | /carta | Ver todos los platos |
POST | /carta | Añadir un plato |
DELETE | /carta/3 | Eliminar el plato con id=3 |
Nuevo proyecto de NodeJS
Abrimos un terminal y nos creamos un nuevo directorio, en este ejemplo, el nombre que le vamos a dar es rest_server (ya que es para un restaurante). Así que después del mkdir rest_server
y cd rest_server
ejecutamos los siguientes comandos para iniciar nuestro proyecto en Node:
npm init -y
Con el parámetro -y no nos preguntará nada, creando un proyecto con el mismo nombre que el directorio. El resultado es un package.json con el siguiente contenido:
{
"name": "rest_server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
A continuación podemos abrir el directorio de nuestro proyecto en Visual Studio Code, podemos arrastrar el directorio a la aplicación (en macOS), podemos abrir el directorio desde dentro de Visual Studio o podemos simplemente ejecutar en el terminal el comando code .
desde dentro del directorio del proyecto.
Creamos un nuevo archivo en la raíz de nuestro proyecto que llamaremos .env en el que editaremos nuestras variables de entorno, el puerto en el que correrá el servidor, el host de nuestra base de datos, el usuario y la contraseña de la base de datos y por último el nombre de la base de datos que previamente habremos creado.
PORT=3300
DBHOST=localhost
DBUSER=root
DBPASS=root
DBNAME=nodedb
Paquetes necesarios
A continuación instalamos en nuestro proyecto los siguientes paquetes:
npm i mysql express nodemon dotenv --save-dev
Indicamos con el parámetro --save-dev que se trata de dependencias de desarrollo únicamente. Con la ejecución del comando anterior nuestro package.json quedará de la siguiente manera:
{
"name": "carta_server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"dotenv": "^8.2.0",
"express": "^4.17.1",
"mysql": "^2.18.1",
"nodemon": "^2.0.7"
}
}
Hay un paquete que ahora ya no es necesario porque el propio Express lo incorpora, este paquete es el conocido body-parser. Si estás usando Express en la versión 4.16.4 o superior no será necesaria su instalación porque ya viene por defecto como una dependencia, con las funciones express.json() y express.urlencoded().
A por el código
Una vez preparado todo el terreno ya podemos empezar a codificar nuestro servidor:
En primer lugar vamos a solucionar la conexión con la base de datos. Creamos y editamos un nuevo archivo en la raíz de nuestro proyecto al que hemos bautizado como config.db.js:
//dotenv nos permite leer las variables de entorno de nuestro .env
const dotenv = require("dotenv");
dotenv.config();
const mysql = require('mysql');
let connection;
try {
connection = mysql.createConnection({
host: process.env.DBHOST,
user: process.env.DBUSER,
password: process.env.DBPASS,
database: process.env.DBNAME
});
} catch (error) {
console.log("Error al conectar con la base de datos");
}
module.exports = {connection};
También en la raíz, creamos el archivo index.js con el siguiente código:
const express = require("express");
const app = express();
//nos ayuda a analizar el cuerpo de la solicitud POST
app.use(express.json());
app.use(express.urlencoded({extended: true}));
//cargamos el archivo de rutas
app.use(require('./routes/carta'));
app.listen(process.env.PORT||3300,() => {
console.log("Servidor corriendo en el puerto 3300");
});
module.exports = app;
A continuación, creamos un directorio al que llamaremos routes y dentro creamos el archivo carta.js con los métodos GET, POST y DELETE:
const express = require("express");
const app = express();
const dotenv = require("dotenv");
dotenv.config();
//conexión con la base de datos
const {connection} = require("../config.db");
const getCarta = (request, response) => {
connection.query("SELECT * FROM carta",
(error, results) => {
if(error)
throw error;
response.status(200).json(results);
});
};
//ruta
app.route("/carta")
.get(getCarta);
const postCarta = (request, response) => {
const {plato, descripcion, precio, disponible} = request.body;
connection.query("INSERT INTO carta(plato, descripcion, precio, disponible) VALUES (?,?,?,?) ",
[plato, descripcion, precio, disponible],
(error, results) => {
if(error)
throw error;
response.status(201).json({"Item añadido correctamente": results.affectedRows});
});
};
//ruta
app.route("/carta")
.post(postCarta);
const delCarta = (request, response) => {
const id = request.params.id;
connection.query("Delete from carta where id = ?",
[id],
(error, results) => {
if(error)
throw error;
response.status(201).json({"Item eliminado":results.affectedRows});
});
};
//ruta
app.route("/carta/:id")
.delete(delCarta);
module.exports = app;
Ejecución
Para terminar vamos a probar que todo funciona correctamente. Abrimos el terminal y ejecutamos el servidor:
nodemon index.js
Deberíamos ver el texto: Servidor corriendo en el puerto 3300.
GET:
Podemos probar el GET des del mismo navegador si no queremos utilizar Postman (o un programa/extensión similar):
En Postman deberíamos ver lo siguiente:
POST:
Vamos ahora a añadir un nuevo plato, en este caso si deberíamos usar Postman (o similar) para hacerlo:
Al ejecutar la solicitud obtenemos el siguiente resultado:
DELETE:
Para probar el método DELETE configuramos Postman de la siguiente manera y ejecutamos (Send):
Conclusión
En un proyecto real nos quedaría mucho trabajo por delante, deberíamos implementar una autenticación basada en token (jsonwebtoken) con sus respectivos middlewares, encriptar contraseñas (con bcryptjs por ejemplo), configurar CORS para permitir solicitudes HTTP entre sitios o validar los datos con Express Validator. Esta entrada pretende ser simplemente una pequeña introducción a todas las posibilidades que nos ofrece NodeJS con Express y MySQL ;)
¡Hasta la próxima!