Hace algún tiempo publiqué un tutorial de como desarollar una API Rest en Node.js con el framework Express. Ese tutorial funciona perfectamente si usas la versión 3.x del framework, pero si vas a cambiar a la versión 4, hay algunas cosas que han cambiado. Es por ello que voy a explicar a continuación como hacer una API REST para vuestras aplicaciones web desde cero, utilizando para ello la versión 4 del framework más usado de Node.js, Express.
Cambios en Express v.4 con respecto a la v.3
En la nueva versión, varios Middlewares han sido eliminados de Express y ahora son dependencias aparte, como es el caso de bodyParser, compress, logger, session, favicon, methodOverride, etc…
Ya no se encuentran dentro del paquete Express y hay que importarlos aparte si se van a usar. De esta manera Express queda más ligero. Por lo tanto uno de nuestros primeros cambios será ese:
{
"name": "node-api-rest-example",
"version": "2.0.0",
"dependencies": {
"mongoose": "~3.6.11",
"express": "^4.7.1",
"method-override": "^2.1.2",
"body-parser": "^1.5.1"
}
}
Nuestro fichero app.js
será así:
var express = require("express"),
app = express(),
bodyParser = require("body-parser"),
methodOverride = require("method-override");
mongoose = require('mongoose');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
var router = express.Router();
router.get('/', function(req, res) {
res.send("Hello World!");
});
app.use(router);
app.listen(3000, function() {
console.log("Node server running on http://localhost:3000");
});
Si os fijáis, antes la declaración de los middlewares a usar, lo hacíamos dentro de app.configure()
, ahora con Express v.4 ya no es necesario.
También se ha eliminado el app.router()
.Ahora las rutas se pueden declarar con app.route(nombre_de_la_ruta)
seguido de los verbos .get()
, .post()
, etc… y podemos crear una instancia para ellas con express.Router()
. En este primer ejemplo vamos hacer que sólo reciba una petición GET
del navegador y muestre en el mismo la frase Hello World
Para ejecutar este pequeño código sólo tienes que escribir en consola lo siguiente y abrir un navegador con la url http://localhost:3000
$ npm install
$ node app.js
Node server running on http://localhost:3000
Si todo va bien, esto es lo que veréis:
Los modelos que vamos a utilizar son los mismos que en el anterior tutorial, y cambian poco en esta versión. Tan solo hay cambios en la forma de declarar las rutas.
Creación de modelos con Mongoose
(Archivo: models/tvshow.js) Este archivo representa el modelo de datos, el cual modelamos con la librería Mongoose. Incluye la información de una serie de TV, como pueden ser su título, el año de inicio, país de producción, una imagen promocional, número de temporadas, género y resumen del argumento:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var tvshowSchema = new Schema({
title: { type: String },
year: { type: Number },
country: { type: String },
poster: { type: String },
seasons: { type: Number },
genre: { type: String, enum:
['Drama', 'Fantasy', 'Sci-Fi', 'Thriller', 'Comedy']
},
summary: { type: String }
});
module.exports = mongoose.model('TVShow', tvshowSchema);
Con esto ya podemos implementar la conexión a la base de datos y la importación de los modelos en el archivo app.js añadiendo las siguientes líneas:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/tvshows', function(err, res) {
if(err) throw err;
console.log('Connected to Database');
});
var models = require('./models/tvshow')(app, mongoose);
Para que esto funcione en nuestro entorno local, necesitamos tener instalado MongoDB. Dependiendo de vuestro sistema operativo de hace de una forma u otra. Aquí tenéis la documentación oficial. Si tenéis Mac, se instala de la misma manera que Node.js:
$ brew update
$ brew install mongodb
Una vez hecho esto, para poder iniciar MongoDB debes ejecutar en otra terminal:
$ mongod
all output going to: /usr/local/var/log/mongodb/mongo.log
Con Mongo arrancado ya podemos ejecutar la aplicación como antes con node app.js
desde la terminal, si todo va bien tendremos algo en la pantalla como esto:
$ node app.js
Node server running on http://localhost:3000
Connected to Database
Ahora desde otra terminal, podemos entrar al shell de MongoDB y comprobar que la base de datos se ha creado correctamente. Para ello ejecutamos el comando mongo
$ mongo
MongoDB shell version: 2.4.1
connecting to: test
> use tvshows
switched to db tvshows
> show dbs
local 0.078125GB
tvshows (empty)
>_
Controladores
Las los controladores de las rutas de nuestro API los vamos a crear en un archivo aparte que llamaremos controllers/tvshows.js. Gracias a exports
conseguimos modularizarlo y que pueda ser llamado desde el archivo principal de la aplicación. El código de a continuación es el comienzo del archivo con la primera función que será la que devuelva todos los registros almacenados:
//File: controllers/tvshows.js
var mongoose = require('mongoose');
var TVShow = mongoose.model('TVShow');
//GET - Return all tvshows in the DB
exports.findAllTVShows = function(req, res) {
TVShow.find(function(err, tvshows) {
if(err) res.send(500, err.message);
console.log('GET /tvshows')
res.status(200).jsonp(tvshows);
});
};
De esta manera tan sencilla, al llamar a esta función findAllTVShows
se envia como respuesta toda la colección de “tvshows” almacenada y en formato JSON. Si queremos que solo nos devuelva un registro con un identificador único, tenemos que crear una función tal que la siguiente:
/GET - Return a TVShow with specified ID
exports.findById = function(req, res) {
TVShow.findById(req.params.id, function(err, tvshow) {
if(err) return res.send(500. err.message);
console.log('GET /tvshow/' + req.params.id);
res.status(200).jsonp(tvshow);
});
};
Con las funciones find()
y findById()
podemos buscar en la base de datos a partir de un modelo. Ahora vamos a desarrollar el resto de funciones que nos permitirán insertar, actualizar y borrar registros de la base de datos. La función de a continuación sería la correspondiente al método POST
y nos permitirá añadir un nuevo objeto a la base de datos:
//POST - Insert a new TVShow in the DB
exports.addTVShow = function(req, res) {
console.log('POST');
console.log(req.body);
var tvshow = new TVShow({
title: req.body.title,
year: req.body.year,
country: req.body.country,
poster: req.body.poster,
seasons: req.body.seasons,
genre: req.body.genre,
summary: req.body.summary
});
tvshow.save(function(err, tvshow) {
if(err) return res.send(500, err.message);
res.status(200).jsonp(tvshow);
});
};
Primero creamos un nuevo objeto tvshow
siguiendo el patrón del modelo, recogiendo los valores del cuerpo de la petición, lo salvamos en la base de datos con el comando .save()
y por último lo enviamos en la respuesta de la función.
La siguiente función nos permitirá actualizar un registro a partir de un ID. Primero buscamos en la base de datos el registro dado el ID, y actualizamos sus campos con los valores que trae el cuerpo de la petición
//PUT - Update a register already exists
exports.updateTVShow = function(req, res) {
TVShow.findById(req.params.id, function(err, tvshow) {
tvshow.title = req.body.petId;
tvshow.year = req.body.year;
tvshow.country = req.body.country;
tvshow.poster = req.body.poster;
tvshow.seasons = req.body.seasons;
tvshow.genre = req.body.genre;
tvshow.summary = req.body.summary;
tvshow.save(function(err) {
if(err) return res.send(500, err.message);
res.status(200).jsonp(tvshow);
});
});
};
Y por último para completar la funcionalidad CRUD
de nuestra API, necesitamos la función que nos permita elminar registros de la base de datos y eso lo podemos hacer con el código de a continuación:
//DELETE - Delete a TVShow with specified ID
exports.deleteTVShow = function(req, res) {
TVShow.findById(req.params.id, function(err, tvshow) {
tvshow.remove(function(err) {
if(err) return res.send(500, err.message);
res.status(200);
})
});
};
Volvemos a nuestro archivo principal, app.js
y declaramos las rutas, siguiendo las pautas de Express v.4
var TVShowCtrl = require('./controllers/tvshows');
// API routes
var tvshows = express.Router();
tvshows.route('/tvshows')
.get(TVShowCtrl.findAllTVShows)
.post(TVShowCtrl.addTVShow);
tvshows.route('/tvshows/:id')
.get(TVShowCtrl.findById)
.put(TVShowCtrl.updateTVShow)
.delete(TVShowCtrl.deleteTVShow);
app.use('/api', tvshows);
Para probarlo seguimos los mismos pasos que hicimos en el tutorial de la versión 3 y tendremos nuestra API REST funcionando.
El código completo de este tutorial lo puedes en este repositorio de GitHub, en la rama feature-express4. Espero que os sirva!