Anuncios

Bienvenidos sean a este post, hoy continuaremos con el tema de los usuarios.

Anuncios

En el post anterior establecimos como seria el modelo encargado de administrar todos nuestros usuarios porque como en la vida real estos son administrados mediante un servidor u otro dispositivo, lo cual nos permitira no solo integrarlo a nuestra aplicacion notas sino a otros, para crear a este servidor necesitaremos el codigo que creamos en el post anterior, sino lo poseen les dejo un link para descargarlo:

Anuncios

Una vez descargado simplemente extraigan el directorio en el PC y ya tenemos nuestra aplicacion lista para ser usada, nuestro primer paso sera ir al archivo package.json y debemos cambiar el valor de main de la siguiente manera:

"main": "user-server.mjs",
Anuncios

En este caso cambiaremos a cual archivo usaremos como principal, dentro del mismo archivo en la seccion scripts agregaremos la siguiente linea:

"start": "cross-env DEBUG=users:* PORT=5858 SEQUELIZE_CONNECT=sequelizar-sqliste.yaml node ./user-server.mjs",
Anuncios

Esta se encargara de iniciar nuestro servidor e indicar cual sera nuestro archivo de conexion a la base de datos, nuestro siguiente paso sera crear un nuevo archivo con el nombre de user-server.mjs y le agregaremos el siguiente codigo:

user-server.mjs

import restify from 'restify';
import * as util from 'util';
import { SQUser, conectarDB, paramsUser, encuentraUser,
crearUser, clarificaUser } from './users-sequelizar.mjs';
import DBG from 'debug';
const log = DBG('users:service');
const error = DBG('users:error');

var server = restify.createServer({
name: "user-auth-server",
version: "0.0.1"
});

server.use(restify.plugins.authorizationParser());
server.use(chequear);
server.use(restify.plugins.queryParser());
server.use(restify.plugins.bodyParser({
mapParams: true
}));

server.listen(process.env.PORT, "127.0.0.1", function() {
log(server.name + ' escuchando en ' + server.url);
});

process.on('uncaughtException', function(err) {
console.error("EXCEPCION SIN CAPTURAR - " + (err.stack || err));
process.exit(1);
});

process.on('unhandledRejection', (reason, p) => {
console.error(
`RECHAZO DE PROMESA: ${util.inspect(p)} razon: ${reason}`);
process.exit(1);
});
Anuncios
Anuncios

Lo primero que haremos sera importar los modulos necesarios y el modulo que creamos en el post anterior, tambien tenemos el segmento habitual encargado de mostrar los mensajes para depuracion (debug), despues tenemos un objeto que se encargara de crear el servidor de tipo REST mediante restify, este es muy similar a Express, donde pasaremos el nombre y la version, despues mediante use aplicaremos varios plugins, veamos estos:

  • authorizationParser, este se encarga de analizar el encabezado de autorizacion como mejor puede hacerlo restify
  • chequear, es una funcion que veremos en un momento
  • queryParser, este se encarga de analizar el query HTTP que pasemos
  • bodyParser, bloque tu cadena a leer y analiza el cuerpo de la solicitud HTTP
Anuncios
Anuncios

Estos manejadores son muy similares a las funciones middleware, de lo cual hablamos en este post, y se encargaran automaticamente de cada una de sus tareas para manejar correctamente las solicitudes REST y brindar las respuestas correctas, lo siguiente sera hacer que el servidor quede escuchando al puerto que le informemos mediante una variable de entorno, recuerden que en el script en el archivo package.json le informamos esta variable, y como direccion de conexion le pasamos la de localhost, para luego mostrarlo en la consola, lo siguiente sera manejar dos tipos de errores como son las excepciones sin capturar y las promesas rechazadas sin procesar, en el primer caso tomaremos el error y devolveremos el stack de memoria o el error en si, en cambio en el segundo caso tomaremos la razon y la promesa para luego informar la promesa y la razon de porque se rechazo, nuestro siguiente paso sera agregar la funcion chequear que mencionamos anteriormente y para ello debemos agregar el siguiente codigo:

var apiClaves = [{ usuario: 'them',
clave:'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF'}];

function chequear(req, res, next) {
if (req.authorization && req.authorization.basic) {
var existe = false;
for (let auth of apiClaves) {
if (auth.clave === req.authorization.basic.password
&& auth.usuario === req.authorization.basic.username) {
existe = true;
break;
}
}
if (existe) next();
else {
res.send(401, new Error("No valido"));
next(false);
}
} else {
res.send(500, new Error("Sin clave de autorizacion"));
next(false);
}
}
Anuncios
Anuncios

Primero estableceremos cual sera nuestro id de autenticacion mediante un array donde pasaremos el usuario y la clave de identificacion, esta no es la mejor practica pero por un tema de practicidad lo haremos asi, despues tenemos la funcion chequear, la cual recibira tres argumentos que son los mismo que usamos para las funciones middleware, esto es asi porque trabajara de la misma forma pero con una salvedad con respecto a middleware, el ultimo next debe pasar el valor de false porque de lo contrario continuara y nos devolvera un error, continuando con la funcion tendremos un condicional donde verificaremos si recibimos dos valores a traves de la solicitud (req), en caso de ser verdadero primero definiremos una variable con el valor de false, esta nos servira para saber si el usuario se autentico bien o no.

Anuncios
Anuncios

Luego tenemos un bucle que tomara el map que definimos anteriormente para pasar por todos los elementos de este, dentro de este tenemos un condicional donde verificaremos si la clave y el usuario informados en los argumentos es igual a los que obtuvimos de apiClaves, en caso de ser verdadero establece a la variable de existe como true, es decir que el usuario es correcto y por ultimo mediante break saldremos del bucle, por fuera del bucle tenemos un condicional donde verificaremos si existe posee el valor true y en caso de ser verdadero usaremos un next, de lo contrario enviaremos una notificacion de error y el next con false, por ultimo tenemos un else para el primer condicional donde en caso de no haber pasado los dos valores nos notificara un error y otro next con false, con esto ya tenemos la base de nuestro server para permitir una conexion correcta pero nos faltan varias acciones mas, agreguemos la primera:

server.post('/crear', async (req, res, next) => {
try {
await conectarDB();
let resultado = await crearUser(req);
res.contentType = 'json';
res.send(resultado);
next(false);
} catch (err) {
res.send(500, err);
next(false);
}
});
Anuncios
Anuncios

Este es el primer escuchador que agregaremos y sera el que usaremos para crear nuevos usuarios, los siguientes van a ser similares a este porque todos tendran tres argumentos donde seran el objeto que recibe la informacion (req), el siguiente sera el encargado de devolver lo creado (res) y next para pasar al siguiente caso o bien finalizarlo mediante false, otra estructura que se repetira sera el try/catch donde verificaremos que no ocurra ningun error y como manejarlo en caso de que suceda, en caso de que ocurra un error o excepcion enviara un codigo 500 y la descripcion del error y finalizamos con un next conteniendo false, esto se repetira en los siguientes escuchadores, en el bloque del try primero nos conectaremos mediante conectarDB despues definiremos un objeto donde almacenaremos el resultado de usar la funcion crearUser que vimos en el post anterior, despues estableceremos el tipo de contenido para el objeto de respuesta mediante contentType y lo siguiente sera mediante send enviar el objeto que habiamos creado anteriormente y lo terminamos con next y false, pasemos a agregar el siguiente escuchador:

server.post('/buscar-o-crear', async (req, res, next) => {
try {
await conectarDB();
let usuario = await encuentraUser(req.params.usuario);
if (!usuario) {
usuario = await crearUser(req);
if (!usuario)
throw new Error('Usuario no creado');
}
res.contentType = 'json';
res.send(usuario);
return next(false);
} catch(err) {
res.send(500, err);
next(false);
}
});
Anuncios
Anuncios

Obsserven que la estructura es bastante similar a la anterior pero varia en el bloque try, este escuchador tiene una particularidad porque como indica es utilizado para buscar un usuario e indicar que existe pero cuando no lo haga procedera a crearlo en la base, devuelta en el bloque try nos conectamos a la base mediante conectarDB, definimos un objeto que se encargara de almacenar el resultado devuelto por encuentraUser, ya veremos como llega este dato cuando pasemos al siguiente post, luego chequearemos si no se devolvio nada, es decir que no se encontro al usuario, y otra vez mediante este objeto almacenaremos el resultado de llamar a crearUser (como en el caso anterior) y volvemos a verificar si no devolvio nada, es decir fallo al crear el usuario, informando que no se pudo crear el usuario.

Anuncios

En cualquiera de los dos casos, ya sea que se encontro o se haya creado correctamente pasaremos a establecer nuevamente el tipo de contenido para el objeto de salida y despues enviaremos el resultado almacenado en salida, y como siempre usaremos un next false, este escuchador puede no tener mucho sentido ahora pero cuando lo integremos con notas veremos porque es necesario pero no quiero adelantar mucho mas, continuemos agregando el siguiente escuchador:

server.get('/buscar/:username', async (req, res, next) => {
try {
await conectarDB();
const usuario = await encuentraUser(req.params.username);
if (!usuario) {
res.send(404,
new Error("No encontado " +
req.params.username));
} else {
res.contentType = 'json';
res.send(usuario);
}
next(false);
} catch(err) {
res.send(500, err);
next(false);
}
});
Anuncios
Anuncios

Este sera el encargado de buscar un usuario determinado, como curiosidad observen que al momento de llamarlo recibe un parametro, en este caso el usuario mediante el parametro username, volvemos a usar la misma estructura que en el escuchador anterior y usamos a encuentraUser donde le pasaremos el argumento que mencionamos anteriormente, y aqui verificara si el valor esta vacio y en caso de ser verdadero procede a enviar el error 404 para indicar que no fue encontrado, en caso contrario vuelve a generar el tipo de contenido y envia el objeto devuelto, este fue sencillo podemos pasar a agregar al siguiente escuchador:

server.get('/listar', async (req, res, next) => {
try {
await conectarDB();
let lista = await SQUser.findAll({});
lista = lista.map(usuario => clarificaUser(usuario));
if (!lista) lista = [];
res.contentType = 'json';
res.send(lista);
next(false);
} catch (err) {
res.send(500, err);
next(false);
}
});
Anuncios
Anuncios

Este se encargara de devolvernos el listado de usuarios en nuestra base, en este caso despues de conectarnos a la base en un objeto almacenaremos el resultado devuelto por el metodo findAll, observen que lo pasamos sin parametro, de ese objeto devuelto mediante el metodo map iremos tomando cada elemento devuelto y crearemos un objeto de tipo Map, y para dejar la informacion lo mas limpia posible se utiliza a clarificaUser y en este caso pasamos el usuario para identificarlo a su vez esta sera la clave que se relacionara con los valores, despues tenemos un condicional donde en caso de que lista este vacio genera un array vacio, en cualquiera de los dos casos obtendremos una salida y podremos enviar mediante el send, ya lo veremos pronto en accion, pasemos a agregar el siguiente escuchador:

server.post('/cambiar/:username', async (req, res, next) => {
try {
await conectarDB();
let acambiar = paramsUser(req);
await SQUser.update(acambiar, { where: { usuario:
req.params.username }});
const resultado = await encuentraUser(req.params.username);
res.contentType='json';
res.send(resultado);
next(false);
} catch (err) {
res.send(500, err);
next(false);
}
});
Anuncios
Anuncios

Este nos brindara la posibilidad de poder modificar y actualizar los datos de los usuarios ya existentes, al igual que en el caso de buscar le pasaremos un argumento que sera el usuario en cuestion, despues de conectarnos a la base definiremos un objeto donde almacenaremos el resultado de paramsUser, el cual nos establece los datos que le pasemos con la estructura correcta para ser cargados en la base y recuerden que req son los datos que le pasaremos cuando apliquemos este escuchador, lo siguiente sera usar el metodo update para actualizar los valores y en este caso le pasaremos los datos estructurados en acambiar, observen que usamos un where que establece el condicional sobre que datos debemos modificar y como valor usamos el usuario que pasamos, por ultimo volvemos a usar encuentraUser para tomar los valores modificados y devolverlos mediante send, pasemos a agregar el siguiente escuchador:

server.del('/borrar/:username', async (req, res, next) => {
try {
await conectarDB();
const usuario = await SQUser.findOne({
where: { usuario: req.params.username }});
if (!usuario) {
res.send(404,
new Error(`${req.params.username} no encontrado`));
} else {
usuario.destroy();
res.contentType = 'json';
res.send(req.params.username);
}
next(false);
} catch(err) {
res.send(500, err);
next(false);
}
});
Anuncios

Este sera el encargado de borrar el usuario que le informemos, para ello primero lo buscaremos mediante el metodo findOne y lo almacenaremos en un objeto, al igual que en el caso de buscar tenemos un condicional donde si el objeto anterior no posee ningun valor devolveremos un error 404 e informaremos que no existe, en caso contrario a ese objeto le aplicamos el metodo destroy que se encarga de borrarlo de la base y devolveremos el valor que pasamos como argumento para saber cual usuario se elimino, por ultimo vamos a agregar el siguiente escuchador:

server.post('/chequear', async (req, res, next) => {
try {
await conectarDB();
const usuario = await SQUser.findOne({
where: { usuario: req.params.usuario }});
let existe;
if (!usuario) {
existe = {
check: false,
usuario: req.params.username,
message: "Usuario no encontrado"
};
} else if (usuario.usuario === req.params.usuario
&& usuario.clave === req.params.clave) {
existe = { check: true,
usuario: usuario.usuario };
} else {
existe = { check: false,
usuario: req.params.usuario,
message: "Clave incorrecta"
};
}
res.contentType = 'json';
res.send(existe);
next(false);
} catch (err) {
res.send(500, err);
next(false);
}
});
Anuncios

Este se encargara de chequear la contraseña de nuestro usuario, esto en la vida real no deben hacerlo pero para practicar un poco no esta mal, en este caso vamos a tratar de validar cual es la contraseña del usuario, para este caso podremos tener tres posibles estados:

  • La contraseña valida
  • La contraseña no valida
  • Usuario no encontrado
Anuncios
Anuncios

Volviendo a este bloque de codigo, primero buscaremos al usuario en cuestion, despues declaramos una variable en blanco por el momento, lo sguiente sera un condicional donde verificamos si no se devolvio un valor, en caso de ser verdadero, estableceremos a la variable vacia con tres valores de propiedad, el primero sera check con false, el siguiente sera el usuario y por ultimo el mensaje indicando que el usuario no fue encontrado, despues tendremos un else if donde verificamos si el valor de contraseña en la base y el informado coinciden y en caso de ser afirmativo procedemos a repetir lo anterior en la variable existe pero esta vez check llevara el valor de true y estableceremos la propiedad de usuario, y por ultimo tenemos un else donde al no cumplirse nada de lo anterior procede nuevamente establece tres propiedades para existe y al igual que en el primer caso establecemos a check como false, el usuario y por ultimo en el mensaje le decimos que la clave es incorrecta, despues finalmente pasaremos mediante send al objeto existe con los valores ingresados, con esto tenemos nuestro «servidor», podemos iniciarlo y comenzar a escuchar en el puerto que le establecimos pero necesitaremos un cliente para usarlo y esto sera tema del proximo post.

Anuncios

Antes de finalizar les dejo un link con todos los archivos del proyecto y los codigos trabajados en este post:

Anuncios

En resumen, hoy hemos creado el servidor que se encargara de contener a nuestros servidores pero a su vez se encargara de recibir todas nuestras solicitudes para hacer el ABM de los usuarios en el servidor, asi como algunas tareas mas, espero les haya resultado curioso sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donación

Es para mantenimento del sitio, gracias!

$1.50