Estructura de una API Rest con NodeJS, Express y MongoDB
En este artículo encontrarán algunas anotaciones y una forma de organizar la estructura de carpetas de una API Rest utilizando nodejs, express y mongoDB.
Pasos que he realizado:
- Instalar MongoDB.
- Crear una base de datos con MongoDB.
- Instalar las dependencias (Fichero de configuración principal package.json).
- Hacer la conexión a MongoDB desde NodeJS con Mongoose. (en el index.js).
- Crear el servidor web con NodeJS. API RESTful en Node.js (en el app.js).
- Cargar el fichero app.js con la configuración de Express (en el index.js).
- Crear los esquemas y modelos.
- Crear un controlador.
- Crear la ruta para el controlador.
- Importar y cargar las rutas en el servidor (app.js).
- Testear mi api con Postman.
Algunos conceptos y dependencias básicas
NodeJS: Es una plataforma o entorno de ejecución para desarrollar con javascript del lado del servidor.
ExpressJS: Es un framework sobre nodejs que nos permite trabajar con el protocolo http y tener sistemas de rutas.
MongoDB: Es una base de datos NoSQL que nos permite trabajar con documentos json binarios (bson), en lugar de utilizar el sistema clásico de tablas y relaciones, lo que hace que sea muy veloz. Tiene colecciones de documentos y estos documentos son objetos json (bson) y los datos se almacenan de manera binaria para aumentar le rendimiento.
Nodemon: Utilidad para monitorear y reiniciar el servidor automáticamente ante cualquier cambio.
body-parser: Nos permite convertir los datos que nos llegan en las peticiones al servidor en objetos JSON.
Bcrypt-nodejs: Librería para encriptar contraseñas con el metodo bcrypt.
Connect-multiparty: Librería para subir ficheros.
Mongoose: Es un modulo y una especie de ORM que nos provee métodos y funcionalidades para trabajar mejor con mongoDB.
Jwt-simple: Librería para la gestión de tokens (nos permite realizar autenticación y cifrado de tokens).
Moment: Librería para trabajar con fechar.
Moongose-pagination: Librería para hacer paginados.
Middlewares: Es un bloque de código que se ejecuta entre la petición que hace el usuario (request) hasta que la petición llega al servidor.
Modelos: Representan una entidad de nuestra base de datos, más concretamente un único registro o documento. Son una abstracción que vamos a utilizar para realizar operaciones en la base de datos. (Están definidos por un esquema).
Esquemas: Son la estructura de una colección, con estructura me refiero a los atributos de cada colección que se vaya a crear.
Estructura del proyecto
La estructura inicial del proyecto contiene en la raíz un archivo package.json donde vamos a especificar la información de nuestro paquete con sus dependencias, un archivo index.js para la conexión a la base de datos y configuración general de mongoose, un app.js para crear el servidor web con NodeJS y la configuración de express, un directorio para nuestros middlewares, un directorio de models para crear los modelos y esquemas, un directorio de controllers para crear las acciones y operaciones sobre nuestra base de datos, y finalmente, un directorio de rutas el que definimos las rutas a las que responderá nuestra aplicación.
package.json
Es el archivo de configuración principal del proyecto y debe encontrarse en la raíz del mismo. En él debe estar reflejado el nombre del proyecto, versión, descripción, scripts, autor, tipo de licencia y algo muy importante las dependencias.
{
"name": "mi-api-rest",
"version": "1.0.0",
"description": "Proyecto api rest ejemplo",
"main": "index.js",
"scripts": {
"start": "nodemon index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "William Bastidas",
"license": "MIT",
"dependencies": {
"bcrypt-nodejs": "0.0.3",
"body-parser": "^1.18.2",
"connect-multiparty": "^2.1.0",
"express": "^4.16.2",
"jwt-simple": "^0.5.1",
"moment": "^2.20.1",
"mongoose": "^5.0.1",
"mongoose-pagination": "^1.0.0"
},
"devDependencies": {
"nodemon": "^1.14.12"
}
}
index.js
Es el archivo para conectar NodeJS con MongoDB (en el hacemos la conexión a la base de datos y configuración general de mongoose)
// Utilizar funcionalidades del Ecmascript 6
'use strict'// Cargamos el módulo de mongoose para poder conectarnos a MongoDB
var mongoose = require('mongoose');// *Cargamos el fichero app.js con la configuración de Express
var app = require('./app');// Creamos la variable PORT para indicar el puerto en el que va a funcionar el servidor
var port = 3800;// Le indicamos a Mongoose que haremos la conexión con Promesas
mongoose.Promise = global.Promise;// Usamos el método connect para conectarnos a nuestra base de datos
mongoose.connect('mongodb://localhost:27017/curso_mean_social', { useMongoClient: true})
.then(() => { // Cuando se realiza la conexión, lanzamos este mensaje por consola
console.log("La conexión a la base de datos curso_mean_social se ha realizado correctamente")
// CREAR EL SERVIDOR WEB CON NODEJS
app.listen(port, () => {
console.log("servidor corriendo en http://localhost:3800");
});
})
// Si no se conecta correctamente escupimos el error
.catch(err => console.log(err));
app.js
Es el archivo para crear el servidor web con NodeJS, contiene la configuración de express. En el también importamos y cargamos las rutas después de crearlas.
// Utilizar funcionalidades del Ecmascript 6
'use strict'// Cargamos los módulos de express y body-parser
var express = require('express');
var bodyParser = require('body-parser');// Llamamos a express para poder crear el servidor
var app = express();// Importamos las rutas
var user_routes = require('./routes/user'); //cargar middlewares
//un metodo que se ejecuta antes que llegue a un controlador
//Configuramos bodyParser para que convierta el body de nuestras peticiones a JSON
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());// Cargamos las rutas
app.use('/api', user_routes);// exportamos este módulo para poder usar la variable app fuera de este archivo
module.exports = app;
models/user.js
archivo para crear los esquema y modelo User.
'use strict'// Cargamos el módulo de mongoose
var mongoose = require('mongoose');// Usaremos los esquemas
var Schema = mongoose.Schema;// Creamos el objeto del esquema y sus atributos
var UserSchema = Schema({
name: String,
surname: String,
nick: String,
email: String,
password: String,
role: String,
image: String
});// Exportamos el modelo para usarlo en otros ficheros
module.exports = mongoose.model('User', UserSchema);
middlewares/authenticated.js
Archivo con el middleware para validar la autenticación del usuario.
'user strict'var jwt = require('jwt-simple');
var moment = require('moment');
var secret = 'clave_secreta_';exports.ensureAuth = function(req, res, next){
if(!req.headers.authorization){
return res.status(403).send({message: 'La peticion no tiene la cabecera de autenticación'});
} else {
var token = req.headers.authorization.replace(/['"]+/g, '');try{
var payload = jwt.decode(token, secret);if(payload.exp > moment().unix()){
return res.status(401).send({
message: 'EL token ha expirado'
});
}
} catch (ex){
return res.status(404).send({
message: 'EL token no es valido'
});
}req.user = payload;next();
}
}
controller/user.js
Archivo controlador de ejemplo. En el programamos las acciones y operaciones sobre nuestra base de datos, en este caso para obtener los datos de un usuario.
'use strict'// Cargamos los modelos para usarlos posteriormente
var User = require('../models/user');
// Conseguir datos de un usuariofunction getUser(req, res){
var userId = req.params.id;//buscar un documento por un id
User.findById(userId, (err, user) => {
if(err)return res.status(500).send({message: 'Error en la petición'});if(!user) return res.status(404).send({message: 'EL usuario no existe'});followThisUser(req.user.sub, userId).then((value) => {
user.password = undefined;
return res.status(200).send({
user,
following: value.following,
followed: value.followed
});
});
});
}
routes/user.js
Archivo en el que definimos las rutas (path) a las que responderá nuestra aplicación y en ellas se encontrará la lógica a ejecutar.
'use strict'// Cargamos el módulo de express para poder crear rutas
var express = require('express');// Cargamos el controlador
var UserController = require('../controllers/user');// Llamamos al router
var api = express.Router();var md_auth = require('../middlewares/authenticated');// Creamos una ruta para los métodos que tenemos en nuestros controladores
api.get('/user/:id', md_auth.ensureAuth, UserController.getUser);// Exportamos la configuración
module.exports = api;