Conceptos Basicos
[Link], es un entorno en tiempo de ejecución multiplataforma, de código abierto, para la capa del
servidor basado en el lenguaje de programación ECMAScript, asíncrono, con I/O de datos en una
arquitectura orientada a eventos y basado en el motor V8 de Google.
Si deseas aprender a instalar [Link] te invito a mi siguiente post
Articulo completo
API REST, es cualquier interfaz entre sistemas que use HTTP para obtener datos o generar
operaciones sobre esos datos en todos los formatos posibles, como XML y JSON. Las operaciones
más importantes relacionadas con los datos en cualquier sistema REST y la especificación HTTP son
cuatro: POST (crear), GET (leer y consultar), PUT (editar) y DELETE (eliminar).
JWT, JSON Web Token (abreviado JWT) es un estándar abierto basado en JSON propuesto por IETF
(RFC 7519) para la creación de tokens de acceso que permiten la propagación de identidad y
privilegios. Articulo Completo
Bcrypt, es una función de hashing de passwords diseñado por Niels Provos y David Maxieres, basado
en el cifrado de Blowfish. Se usa por defecto en sistemas OpenBSD y algunas distribuciones Linux y
SUSE. Lleva incorporado un valor llamado salt, que es un fragmento aleatorio que se usará para
generar el hash asociado a la password, y se guardará junto con ella en la base de datos. Así se evita
que dos passwords iguales generen el mismo hash y los problemas que ello conlleva, por ejemplo,
ataque por fuerza bruta a todas las passwords del sistema a la vez.
Articulo Completo
[Link], Es un framework para [Link] que sirve para ayudarnos a crear aplicaciones web en
menos tiempo ya que nos proporciona funcionalidades como el enrutamiento, opciones para
gestionar sesiones y cookies, entre otras cosas.
Articulo Completo
Mongodb, es un sistema de base de datos NoSQL orientado a documentos de código abierto.
En lugar de guardar los datos en tablas, tal y como se hace en las bases de datos relacionales,
MongoDB guarda estructuras de datos BSON (una especificación similar a JSON) con un esquema
dinámico, haciendo que la integración de los datos en ciertas aplicaciones sea más fácil y rápida.
Articulo Completo
Flujo de Trabajo
Registro de usuario a través del formulario de registro. (Nombre, Email, Contraseña)
El usuario se autentica mediante correo electrónico y contraseña.
Para poder consumir los recursos protegidos, el usuario debe enviar el token JWT en el encabezado.
Desarrollando nuestra API
Vamos a iniciar creando una carpeta donde almacenaremos nuestro proyecto y luego de eso
ejecutamos el comando npm init para la creaccion de nuestra API.
mkdir API-REST-NODEJS ----> Crear carpeta en linux con el binario MKDIR
cd API-REST-NODEJS ----> Nos dirigimos a la carpeta contenedora de nuestro proyecto
npm init ----> Inicializacion de un proyecto con NPM
Que es el archivo [Link]
Con el comando npm init se crea un archivo llamado [Link]. En este archivo, queda reflejada
la configuración del proyecto de NodeJs tales como:
Nombre del proyecto.
Autor.
Version.
Dependencias.
Scripts.
Repositorio Git.
El contenido del archivo debería tener una estructura similar a esta:
"name": "olimpo",
"version": "1.0.0",
"description": "Construyendo una API REST con NodeJS",
"main": "[Link]",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Gerh",
"license": "MIT"
Ahora debemos instalar las siguientes dependencias:
╭─[/home/gerh/Escritorio/Prometheus/MyCodes/Blog/API-REST-
NODEJS]─[root@Raeghal]─[0]─[1112]
╰─[:)] # npm install bcrypt body-parser express jsonwebtoken mongoose morgan --save
╭─[/home/gerh/Escritorio/Prometheus/MyCodes/Blog/API-REST-
NODEJS]─[root@Raeghal]─[0]─[1112]
╰─[:)] # npm install nodemon -g
Cada dependencia cumplira con un papel importante en nuestro desarrollo:
Para que sirven las dependecias previamente instaladas?
bcrypt, Esta dependencia nos ayudara a hashear de manera simple las contraseñas de los usuarios.
De esta manera, garantizamos la confidencialidad de estos datos sensibles que estaran almacenados
en nuestra base de datos.
body-parser, Con esta dependencia vamos a extraer toda la parte del cuerpo de un flujo de solicitud
entrante y lo expone en [Link]; como algo con lo que es más fácil interactuar.
Mongoose, es una herramienta de modelado de objetos MongoDB diseñada para trabajar en un
entorno asíncrono.
Morgan, Es middleware del registrador de solicitudes HTTP para [Link]
Nodemon, Esta dependencia observará los archivos en el directorio en el que se inició nodemon, y
si cualquier archivo cambia, nodemon reiniciará automáticamente su aplicación de [Link].
Después de instalar las dependencias, su archivo [Link] tendrá la lista de todas las
dependencias instaladas:
"dependencies": {
"bcrypt": "^3.0.6",
"body-parser": "^1.19.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.5.14",
"morgan": "^1.9.1"
Creando nuestra estructura de directorios
Ahora que hemos finalizado la instalacion de estas dependencias podemos continuar creando las
carpetas que contendran toda la logica del API REST.
cd API-REST-NODEJS ===> Accediendo a nuestro directorio principal
mkdir config ===> Creando el directorio Config
mkdir routes ===> Creando el directorio routes
mkdir app ===> Creando el directorio app
cd app ===> Entramos al directorio app
mkdir api ===> Creando el directorio api
cd api ===> Entramos al directorio api
mkdir controllers ===> Creando el directorio controllers
mkdir models ===> Creando el directorio models
Utilizando el patron MVC
Para este desarrollo utilizaremos el patron Modelo Vista Controlador (MVC), El cual es un estilo de
arquitectura de software que separa los datos de una aplicación, la interfaz de usuario, y la lógica
de control en tres componentes distintos.
Creando un servidor con [Link] y [Link]
Creamos un archivo con el nombre “[Link]” dentro del directorio raiz y su contenido sera el
siguiente:
const express = require('express');
const logger = require('morgan');
const bodyParser = require('body-parser');
const app = express();
[Link](logger('dev'));
[Link]([Link]({extended: false}));
[Link]('/', function(req, res){
[Link]({"tutorial" : "Construyendo una API REST con NodeJS"});
});
[Link](3000, function(){ [Link]('El servidor ha sido inicializado: [Link]
Para validar todo lo que hemos hecho, vamos a inicializar nuestro servidor con el siguiente
comando:
╭─[/home/gerh/Escritorio/Prometheus/MyCodes/Blog/API-REST-
NODEJS]─[root@Raeghal]─[0]─[1137]
╰─[:)] # nodemon [Link]
[nodemon] 1.19.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node [Link]`
El servidor ha sido inicializado: [Link]
Luego de ello, si accedemos a nuestro navegador con el link [Link] deberia
respondernos lo siguiente:
tutorial: "Construyendo una API REST con NodeJS"
Creaccion de modelos y entidades con [Link]
Los modelos dentro de NodeJS son representaciones de una entidad de la base de datos y más
concretamente van a representar a un único registro o documento de nuestra base de de datos.
Para este tutorial, vamos a tener una colección en la base de datos llamada Usuarios, dentro de ella
se guardarán documentos de tipo Usuario.
Por lo tanto debemos crear un modelo de Usuario con todos sus campos y cuando queramos crear
una usuario haremos una instancia de ese modelo.
Vamos a crear un archivo con el nombre “[Link]”, en la ruta: /API-REST-
NODEJS/app/api/models/[Link]
Dentro de el codificaremos lo siguiente:
// Cargamos el módulo de mongoose
const mongoose = require('mongoose');
// Cargamos el módulo de bcrypt
const bcrypt = require('bcrypt');
// Definimos el factor de costo, el cual controla cuánto tiempo se necesita para calcular un solo hash
de BCrypt. Cuanto mayor sea el factor de costo, más rondas de hash se realizan. Cuanto más tiempo
sea necesario, más difícil será romper el hash con fuerza bruta.
const saltRounds = 10;
//Definimos los esquemas
const Schema = [Link];
// Creamos el objeto del esquema con sus correspondientes campos
const UserSchema = new Schema({
nombre: {
type: String,
trim: true,
required: true,
},
email: {
type: String,
trim: true,
required: true
},
password: {
type: String,
trim: true,
required: true
});
// Antes de almacenar la contraseña en la base de datos la encriptamos con Bcrypt, esto es posible
gracias al middleware de mongoose
[Link]('save', function(next){
[Link] = [Link]([Link], saltRounds);
next();
});
// Exportamos el modelo para usarlo en otros ficheros
[Link] = [Link]('User', UserSchema);
Creacion de controladores
Continuemos creando un controlador para el modelo recien creado, debe estar almacenado en la
ruta /API-REST-NODEJS/app/api/controllers/[Link]:
// Cargamos el modelo recien creado
const userModel = require('../models/users');
// Cargamos el módulo de bcrypt
const bcrypt = require('bcrypt');
// Cargamos el módulo de jsonwebtoken
const jwt = require('jsonwebtoken');
// Codificamos las operaciones que se podran realizar con relacion a los usuarios
[Link] = {
create: function(req, res, next) {
[Link]({ nombre: [Link], email: [Link], password:
[Link] }, function (err, result) {
if (err)
next(err);
else
[Link]({status: "Ok", message: "Usuario agregado exitosamente!!!", data: null});
});
},
authenticate: function(req, res, next) {
[Link]({email:[Link]}, function(err, userInfo){
if (err) {
next(err);
} else {
if([Link]([Link], [Link])) {
const token = [Link]({id: userInfo._id}, [Link]('secretKey'), { expiresIn: '1h' });
[Link]({status:"Ok", message: "El usuario ha sido autenticado!!!", data:{user: userInfo,
token:token}});
}else{
[Link]({status:"error", message: "Invalid email/password!!", data:null});
});
},
Nuestro controlador de usuario incluira el modelo de usuario y los modulos jsonwebtoken y bcrypt.
Tambien hemos definido dos metodos:
Metodo Create
Con este metodo podremos crear nuevos usuarios.
Metodo Authenticate
En este metodo, hemos creado una funcion que realiza una busqueda en la base de datos por medio
del correo electronico, con ello logramos validar la existencia de un usuario.
Luego comparamos la contraseña simple que se envia a través del formulario de inicio de sesión
contra la contraseña de la base de datos; cabe aclarar que si contraseña coincide se generara el
token JWT con una validez de 1 hora.
Creacion de Rutas
Luego de codificar lo anterior, vamos a proceder con la creacion de rutas para los métodos de
control de los usuarios anteriores.
Este archivo debe estar almacenado en /API-REST-NODEJS/routes/[Link]
// Cargamos el modulo express
const express = require('express');
const router = [Link]();
// Cargamos el controlador del usuario
const userController = require('../app/api/controllers/users');
// Especificamos nuestras rutas teniendo en cuenta los metodos creados en nuestro controlador, y
especificando que seran rutas que usaran el metodo POST
[Link]('/register', [Link]);
[Link]('/authenticate', [Link]);
[Link] = router;
Listo, hemos finalizado todo lo relacionado con los usuarios.
Ahora vamos a proceder con la creacion del modelo, el controlador y el archivo de ruta para los
videojuegos.
Creacion de CRUD para videojuegos
Nuestra API tendra la funcionalidad de leer, crear, actualizar y eliminar registros de videojuegos.
Creacion del controlador
Creamos un archivo en la siguiente ruta:
/API-REST-NODEJS/app/api/controllers/[Link]
El contenido debe ser el siguiente:
const videogameModel = require('../models/videogames');
[Link] = {
// Metodo para la busqueda de videojuegos por ID
getById: function(req, res, next) {
[Link]([Link]);
[Link]([Link], function(err, videogameInfo){
if (err) {
next(err);
} else {
[Link]({status:"success", message: "Videogame found!!!", data:{videogames: videogameInfo}});
});
},
//Metodo para retornar todos los videojuegos registrados en la base de datos
getAll: function(req, res, next) {
let videogamesList = [];
[Link]({}, function(err, videogames){
if (err){
next(err);
} else{
for (let videogame of videogames) {
[Link]({id: videogame._id, name: [Link], released_on:
videogame.released_on});
[Link]({status:"success", message: "Videogames list found!!!", data:{videogames:
videogamesList}});
});
},
//Metodo para actualizar algun registro de la base de datos por ID
updateById: function(req, res, next) {
[Link]([Link],{name:[Link]},
function(err, videogameInfo){
if(err)
next(err);
else {
[Link]({status:"success", message: "Videogame updated successfully!!!", data:null});
});
},
//Metodo para eliminar algun registro de la base de datos por ID
deleteById: function(req, res, next) {
[Link]([Link], function(err, videogameInfo){
if(err)
next(err);
else {
[Link]({status:"success", message: "Videogame deleted successfully!!!", data:null});
});
},
//Metodo para crear algun registro nuevo
create: function(req, res, next) {
[Link]({ name: [Link], released_on: [Link].released_on }, function
(err, result) {
if (err)
next(err);
else
[Link]({status: "success", message: "Videogame added successfully!!!", data: null});
});
},
}
Creacion del Modelo
Creamos un archivo en la siguiente ruta:
/API-REST-NODEJS/app/api/models/[Link]
El contenido debe ser el siguiente:
// Cargamos el módulo de mongoose
const mongoose = require('mongoose');
//Definimos el esquema
const Schema = [Link];
// Creamos el objeto del esquema con sus correspondientes campos
const VideogameSchema = new Schema({
name: {
type: String,
trim: true,
required: true,
},
released_on: {
type: Date,
trim: true,
required: true
});
// Exportamos el modelo para usarlo en otros ficheros
[Link] = [Link]('Videogame', VideogameSchema)
Creacion de manejador de rutas
Creamos un archivo en la siguiente ruta:
/API-REST-NODEJS/routes/[Link]
El contenido debe ser el siguiente:
// Cargamos el modulo express
const express = require('express');
const router = [Link]();
// Cargamos el controlador de videojuegos
const videogameController = require('../app/api/controllers/videogames');
// Especificamos nuestras rutas teniendo en cuenta los metodos creados en nuestro controlador
[Link]('/', [Link]);
[Link]('/', [Link]);
[Link]('/:videogameId', [Link]);
[Link]('/:videogameId', [Link]);
[Link]('/:videogameId', [Link]);
[Link] = router;
Finalmente, actualizamos nuestro [Link] con el siguiente contenido:
const express = require('express');
const logger = require('morgan');
const videogames = require('./routes/videogames') ;
const users = require('./routes/users');
const bodyParser = require('body-parser');
const mongoose = require('./config/database'); //Importando la configuracion de conexion a la BD
var jwt = require('jsonwebtoken');
const app = express();
[Link]('secretKey', 'ClaveSecreta'); // Clave Secreta para nuestro JWT
// Conectando a la base de datos de Mongo
[Link]('error', [Link](console, 'Error de conexion en MongoDB'));
[Link](logger('dev'));
[Link]([Link]({extended: false}));
[Link]('/', function(req, res){
[Link]({"tutorial" : "Construyendo una API REST con NodeJS"});
});
// Rutas publicas
[Link]('/users', users);
// Rutas privadas que solo pueden ser consumidas con un token generado
[Link]('/videogames', validateUser, videogames);
[Link]('/[Link]', function(req, res) {
[Link](204);
});
// Para acceder a las rutas de peliculas hemos definido middleware para validar al usuario.
function validateUser(req, res, next) {
[Link]([Link]['x-access-token'], [Link]('secretKey'), function(err, decoded) {
if (err) {
[Link]({status:"error", message: [Link], data:null});
}else{
// add user id to request
[Link] = [Link];
next();
});
// Manejando errores HTTP 404 para solicitudes de contenido inexistente
[Link](function(req, res, next) {
let err = new Error('Not Found');
[Link] = 404;
next(err);
});
// Manejo de errores, respuestas con codigo HTTP 500, HTTP 404
[Link](function(err, req, res, next) {
[Link](err);
if([Link] === 404)
[Link](404).json({message: "Not found"});
else
[Link](500).json({message: "Error interno en el servidor!!"});
});
[Link](3000, function(){
[Link]('El servidor ha sido inicializado: [Link]
});
Configurando el archivo de conexion para MongoDB
Este archivo lo almacenaremos en la siguiente ruta:
/API-REST-NODEJS/config/[Link] Y codificamos lo siguiente:
//Cargando el modulo de mongoose
const mongoose = require('mongoose');
//Configurando la conexion para MongoDB, Debemos indicar el puerto y la IP de nuestra BD
const mongoDB = 'mongodb://[Link]:27017/BinaryChaos';
[Link](mongoDB);
[Link] = [Link];
[Link] = mongoose;
Si deseas aprender a como crear una coleccion
Probando Nuestra API
Las operaciones HTTP disponibles para nuestra API son:
POST (crear un recurso o generalmente proporcionar datos)
GET (recuperar un índice de recursos o un recurso individual)
PUT (actualizar o reemplazar un recurso)
DELETE (eliminar un recurso)
Registro de usuarios.
POST [Link]
Validando el servicio de registro de usuarios.
Servicio de autenticacion, para generar el token
POST [Link]
Validando el servicio de autenticacion
Listado completo de videojuegos sin token de autenticacion
GET [Link]
Intentando consumir un servicio protegido sin ningun token
Listado completo de videojuegos con token de autenticacion
GET [Link]
Consumiendo un servicio protegido con un token de autenticacion
Listado de videojuegos por ID (Listado Dinamico)
GET [Link]
Consumiendo un servicio protegido con un token de autenticacion
Actualizacion de videojuegos por ID
PUT [Link]
Actualizar un registro existente de la base de datos
Eliminacion de videojuegos por ID
DELETE [Link]
Actualizar un registro existente de la base de datos
GERARDO ELIASIB
Ethical Hacker - Developer