Breaking

Post Top Ad

Your Ad Spot

miércoles, 23 de octubre de 2019

Desarrollo de Node.js con JavaScript moderno usando FortJs

Desarrollo de Node.js con JavaScript moderno usando FortJs

Introducción


Nodejs te da el poder de escribir código del lado del servidor usando JavaScript. De hecho, es muy fácil y rápido crear un servidor web usando Nodejs. Hay varios marcos disponibles en el administrador de paquetes Node que hacen que el desarrollo sea aún más fácil y rápido.
Pero hay algunos desafíos en el desarrollo de Nodejs:
  • Nodejs tiene que ver con devoluciones de llamadas, y con más y más devoluciones de llamadas terminas en una situación llamada devolución de llamadas infierno.
  • Escribir código legible.
  • Escribir código mantenible.
  • No obtienes mucho soporte inteligente que hace que el desarrollo sea lento.
Si tiene bastante experiencia y tiene un buen conocimiento de Nodejs, puede usar diferentes técnicas y tratar de minimizar estos desafíos.
La mejor manera de resolver estos problemas es utilizando JavaScript moderno ES6, ES7 o TypeScript, con lo que se sienta cómodo. Recomiendo TypeScript, ya que proporciona soporte intillisense para cada palabra de código que hace que su desarrollo sea más rápido.
Así que creé un marco llamado FortJs que es muy fácil de aprender y usar. FortJs le permite escribir código del lado del servidor utilizando ES6 o TypeScript que es modular, seguro y prácticamente simplemente hermoso y legible.

Caracteristicas


Algunas de las características importantes de FortJs son:  
  • Basado en la arquitectura de Fort .
  • MVC Framework y sigue el enfoque OOPS para que todo sea clase y objeto.
  • Proporciona componentes: pared, escudo y protección. Los componentes ayudan a modularizar la aplicación.
  • Utiliza ES6 asíncrono / en espera o promete ejecutar código asíncrono.
  • Todo es configurable: puede configurar su tienda de sesiones, ver motor, websocket, etc.
  • Inyección de dependencia.
  • Todo puede ser probado en la unidad, por lo que puede utilizar un enfoque TDD .

Codifiquemos


En este artículo, voy a crear una API REST usando FortJs y ES6. Pero también puede usar el mismo código y pasos para implementar usando TypeScript.

Configuración del proyecto


FortJs proporciona una CLI: fort-creator. Esto le ayuda a configurar el proyecto y a desarrollarse más rápido. Usemos la CLI para desarrollar.
Realice los siguientes pasos secuencialmente:
  • Abra su terminal o símbolo del sistema.
  • Instale FortJs globalmente: ejecute el comando "npm i fort-creator -g". Nota: Asegúrese de tener Nodejs instalados en su sistema.
  • Cree un nuevo proyecto: ejecute el comando "fort-creator new my-app". Aquí "my-app" es el nombre de la aplicación, por lo que puede elegir cualquier nombre. La CLI le pedirá que elija el idioma con dos opciones: TypeScript y JavaScript. Elija su idioma con las teclas de flecha y presione Entrar. Como voy a usar ES6, he elegido JavaScript. Tomará algún tiempo crear el proyecto, así que espere hasta que vea "nuevo proyecto creado por mi aplicación".
  • Ingrese al directorio del proyecto - "cd my-app".
    Inicie el servidor de desarrollo con recarga en vivo: ejecute el comando "fort-creator start".
  • Abra el navegador y escriba la URL: http: // localhost: 4000 / .
Deberías ver algo como esto en el navegador.
Página de inicio de FortJs
Comprendamos cómo se representa esta página:
  • Abra la carpeta del proyecto en su editor de código favorito. Voy a usar VS Code. Verá muchas carpetas dentro de la raíz del proyecto, como controladores, vistas, etc. Cada carpeta se agrupa por su uso; por ejemplo, la carpeta de controladores contiene todos los controladores y la carpeta de vistas contiene todas las vistas.
  • Abra la carpeta de controladores -> Dentro de los controladores, verá un nombre de archivo - default_controller. Vamos a abrirlo y observar el código. El archivo contiene una clase DefaultController: esta es una clase de controlador y contiene métodos que devuelven alguna respuesta http.
  • Dentro de la clase DefaultController, verá un método 'index': este es el que está mostrando la salida actual al navegador. El método se conoce como trabajador en FortJs porque hacen algún tipo de trabajo y devuelven el resultado como una respuesta http. Observemos el código del método de índice:

    `` `
    const data = {
       title: title
    }
    const result = await viewResult ('default / index.html', data);
    resultado de retorno;
    ``
    Crea un objeto de datos y lo pasa al método viewResult . El método viewResult toma dos parámetros: la ubicación y los datos de la vista. El trabajo de vistaResultado es representar la vista y devolver una respuesta, que estamos viendo en el navegador.
  • Busquemos el código de vista y comprendamos. Abra la carpeta de vistas -> abra la carpeta predeterminada -> abra index.html. Este es nuestro código de vista. Es un código HTML simple junto con alguna sintaxis de bigote. El motor de vista predeterminado para Fortjs es el bigote.
Espero que hayas entendido la arquitectura del proyecto. Si tiene alguna dificultad o duda, no dude en preguntar en la sección de comentarios.
Ahora pasaremos a la siguiente parte de este artículo, donde aprenderemos cómo crear una API de descanso simple.

DESCANSO

Vamos a crear un punto final REST para el usuario de la entidad, que realizará operaciones CRUD para el usuario, como agregar un usuario, eliminar un usuario, obtener un usuario y actualizar un usuario.
De acuerdo con REST:
  1. Agregar usuario: debe hacerse utilizando el método http " POST"
  2. Eliminar usuario: debe hacerse utilizando el método http " REMOVE"
  3. Conseguir usuario: debe hacerse utilizando el método http " GET"
  4. Actualización de usuario: debe hacerse utilizando el método http " PUT"
Para crear un punto final, necesitamos crear un controlador similar al controlador predeterminado explicado anteriormente.
Ejecute el comando " fort-creator add". Le pedirá que "elija el componente que desea agregar". Elija Controlador y presione Entrar . Ingrese el nombre del controlador "Usuario" y presione Intro .
Ahora que hemos creado el controlador de usuario, debemos informar a FortJs agregándolo a las rutas. La ruta se utiliza para asignar nuestro controlador a una ruta.
Como nuestra entidad es usuario, " /user" será una buena ruta. Vamos a agregarlo. Abra routes.js dentro del directorio raíz del proyecto y agréguelo UserControllera rutas.
Después de agregar UserController, routes.js se verá así:
import { DefaultController } from "./controllers/default_controller";
import { UserController } from "./controllers/user_controller";

export const routes = [{
    path: "/*",
    controller: DefaultController
},
{
    path: "/user",
    controller: UserController
}]
routes.js
Entonces, cuando una solicitud http tiene la ruta "/ user", se llamará a UserController.
Abramos la url: http: // localhost: 4000 / user .
Nota: Si ha detenido FortJs mientras agregaba el controlador, vuelva a iniciarlo ejecutando cmd: fort-creator start
Y ves una página en blanco ¿verdad?
Esto se debe a que no estamos devolviendo nada del método de índice y, por lo tanto, obtenemos una respuesta en blanco. Regresemos un texto "Hola Mundo" del método de índice. Agregue el siguiente código dentro del método de índice y guarde:
return textResult('Hello World');
Y ves "Hola Mundo" ¿verdad?
Ahora, convirtamos "UserController" en una API REST. Pero antes de escribir código para la API REST, creemos un servicio ficticio que realizará operaciones CRUD para los usuarios.

Servicio

Cree una carpeta llamada "servicios" y luego un archivo "user_service.js" dentro de la carpeta. Pegue el siguiente código dentro del archivo:
const store = {
    users: [{
        id: 1,
        name: "ujjwal",
        address: "Bangalore India",
        emailId: "ujjwal@mg.com",
        gender: "male",
        password: "admin"
    }]
}

export class UserService {
    getUsers() {
        return store.users;
    }

    addUser(user) {
        const lastUser = store.users[store.users.length - 1];
        user.id = lastUser == null ? 1 : lastUser.id + 1;
        store.users.push(user);
        return user;
    }

    updateUser(user) {
        const existingUser = store.users.find(qry => qry.id === user.id);
        if (existingUser != null) {
            existingUser.name = user.name;
            existingUser.address = user.address;
            existingUser.gender = user.gender;
            existingUser.emailId = user.emailId;
            return true;
        }
        return false;
    }

    getUser(id) {
        return store.users.find(user => user.id === id);
    }

    removeUser(id) {
        const index = store.users.findIndex(user => user.id === id);
        store.users.splice(index, 1);
    }
}
El código anterior contiene un almacén de variables que contiene una colección de usuarios. El método dentro del servicio realiza operaciones como agregar, actualizar, eliminar y acceder a esa tienda.
Utilizaremos este servicio en la implementación de la API REST.

OBTENER

Para la ruta "/ usuario" con el método http "GET", la API debe devolver una lista de todos los usuarios.
Para implementar esto, cambiemos el nombre del método "index" dentro de user_controller.js por "getUsers", haciéndolo semánticamente correcto. Luego pegue el siguiente código dentro del método:
const service = new UserService();
return jsonResult(service.getUsers());
Ahora user_controller.js se ve así:

import { Controller, DefaultWorker, Worker, textResult, jsonResult } from "fortjs";
import { UserService } from "../services/user_service";

export class UserController extends Controller {

    @DefaultWorker()
    async getUsers() {
        const service = new UserService();
        return jsonResult(service.getUsers());
    }
}
Aquí, estamos usando el decorador DefaultWorker. DefaultWorker hace dos cosas: agrega la ruta "/" y el método http "GET". Es un atajo para este escenario. En la siguiente parte, utilizaremos otros decoradores para personalizar la ruta.
Probemos esto llamando a la url http: // localhost: 4000 / user . Puede abrir esto en el navegador o usar cualquier herramienta de cliente http como cartero o curl.
Ok, hemos creado con éxito un punto final :).
Veamos nuevamente nuestro código y veamos si podemos mejorarlo:
  1. El servicio "UserService" está estrechamente acoplado con el controlador "UserController", lo que se convierte en un problema para las pruebas unitarias "UserController". Entonces usaremos la inyección de dependencia de FortJs para inyectar UserService.
  2. Estamos creando una instancia de "UserService" cada vez que se llama al método getUsers. Pero lo que necesitamos de "UserService" es un solo objeto y luego llamar al método "UserService" desde el objeto.
Entonces, si de alguna manera podemos almacenar un objeto de "UserService", entonces podemos hacer que nuestro código sea más rápido (porque llamar a new hace un poco de trabajo). Para esto usaremos la función singleton de FortJs.
Cambiemos el código user_controller.js por el siguiente código:

import { Controller, DefaultWorker, Worker, textResult, jsonResult, Singleton } from "fortjs";
import { UserService } from "../services/user_service";

export class UserController extends Controller {

    @DefaultWorker()
    async getUsers(@Singleton(UserService) service) {
        return jsonResult(service.getUsers());
    }
}
Como puede ver, el único cambio es que estamos usando el decorador "Singleton" en el método getUsers. Esto creará un singleton e inyectará ese singleton cuando se llame a getUsers. Este singleton estará disponible en toda la aplicación.
Como el servicio ahora es un parámetro, podemos pasar el parámetro manualmente durante una llamada. Esto hace que la unidad getUsers sea comprobable.
Para realizar pruebas unitarias o pruebas E2E, lea este documento de prueba: http://fortjs.info/tutorial/test/

ENVIAR

Agreguemos un método "addUser" que extraerá datos del cuerpo de la solicitud y llamará al servicio para agregar un usuario.
async addUser(@Singleton(UserService) service) {
        const user = {
            name: this.body.name,
            gender: this.body.gender,
            address: this.body.address,
            emailId: this.body.emailId,
            password: this.body.password
        };
        const newUser = service.addUser(user);
        return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}
En el código anterior, estamos creando el Singleton del UserService nuevamente. Entonces la pregunta es ¿creará otro objeto?
No, será el mismo objeto que estaba en getUser. FortJs proporciona el objeto como parámetro cuando llama al método.
Los métodos creados no están visibles por defecto para una solicitud http. Entonces, para que este método sea visible para la solicitud http, debemos marcarlo como trabajador.
Un método se marca como trabajador agregando el decorador "Trabajador". El decorador de trabajadores toma una lista de métodos http y hace que ese método esté disponible solo para esos métodos http. Entonces agreguemos el decorador:
@Worker([HTTP_METHOD.Post])
async addUser(@Singleton(UserService) service) {
    const user = {
        name: this.body.name,
        gender: this.body.gender,
        address: this.body.address,
        emailId: this.body.emailId,
        password: this.body.password
    };
    const newUser = service.addUser(user);
    return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}
Ahora la ruta de este método es la misma que el nombre del método que es "addUser". Puede verificar esto enviando una solicitud de publicación a http: // localhost: 4000 / user / addUser con los datos del usuario en el cuerpo.
Pero queremos que la ruta sea "/", para que sea una API de descanso. La ruta del trabajador se configura mediante el decorador "Ruta". Cambiemos la ruta ahora.
@Worker([HTTP_METHOD.Post])
@Route("/")
async addUser(@Singleton(UserService) service) {
    const user = {
        name: this.body.name,
        gender: this.body.gender,
        address: this.body.address,
        emailId: this.body.emailId,
        password: this.body.password
    };
    const newUser = service.addUser(user);
    return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}
Ahora nuestro punto final está configurado para una solicitud posterior. Probemos esto enviando una solicitud de publicación a http: // localhost: 4000 / user / con los datos del usuario en el cuerpo.
Devuelve el usuario creado con id, que es nuestra lógica. Por lo tanto, hemos creado el punto final para la solicitud posterior, pero una cosa importante es validar los datos. La validación es una parte esencial de cualquier aplicación y es muy importante para una aplicación de fondo.
Hasta ahora, nuestro código es limpio y legible. Pero si agregamos un código de validación, se ensuciará un poco.
No se preocupe, FortJs proporciona el componente Guardia para este tipo de trabajo. A / c para los documentos de FortJs:
Guard es una capa de seguridad encima del trabajador. Controla si se debe permitir que una solicitud llame al Trabajador.
Así que vamos a usar guardia para la validación de los datos. Creemos la guardia usando fort-creator. Ejecute el comando   fort-creator addy elija Guardia. Ingrese el nombre de archivo "UserValidator". Habrá un archivo "user_validator_guard.js" creado dentro de la carpeta de guardias. Abre ese archivo.
Un guardia tiene acceso al cuerpo, por lo que puede validar los datos que contiene. Devolver nulo dentro del método checksignifica que estamos permitiendo llamar al trabajador. Devolver cualquier otra cosa significa bloquear la llamada.
Hagámoslo más claro escribiendo código para la validación. Pegue el siguiente código dentro del archivo "user_validator_guard.js":

import { Guard, textResult, HTTP_STATUS_CODE } from "fortjs";

export class UserValidatorGuard extends Guard {

    async check() {
        const user = {
            name: this.body.name,
            gender: this.body.gender,
            address: this.body.address,
            emailId: this.body.emailId,
            password: this.body.password
        };
        const errMsg = this.validate(user);
        if (errMsg == null) {
            // pass user to worker method, so that they dont need to parse again  
            this.data.user = user;
            // returning null means - guard allows request to pass  
            return null;
        } else {
            return textResult(errMsg, HTTP_STATUS_CODE.BadRequest);
        }
    }
    
    validate(user) {
        let errMessage;
        if (user.name == null || user.name.length < 5) {
            errMessage = "name should be minimum 5 characters"
        } else if (user.password == null || user.password.length < 5) {
            errMessage = "password should be minimum 5 characters";
        } else if (user.gender == null || ["male", "female"].indexOf(user.gender) < 0) {
            errMessage = "gender should be either male or female";
        } else if (user.emailId == null || !this.isValidEmail(user.emailId)) {
            errMessage = "email not valid";
        } else if (user.address == null || user.address.length < 10) {
            errMessage = "address length should be greater than 10";
        }
        return errMessage;
    }
    
    isValidEmail(email) {
        var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return re.test(String(email).toLowerCase());
    }


}
En el código anterior:
  • Hemos creado un método validar que toma el parámetro usuario. Valida al usuario y devuelve el mensaje de error si hay un error de validación, de lo contrario es nulo.
  • Estamos validando datos dentro del método de verificación, que es parte del ciclo de vida de guardia. Estamos validando al usuario dentro de él llamando al método validar.
    Si el usuario es válido, entonces estamos pasando el valor del usuario utilizando la propiedad "data" y devolviendo nulo. Devolver nulo significa que el guardia ha permitido esta solicitud y se debe llamar al trabajador.
  • Si un usuario no es válido, estamos devolviendo un mensaje de error como respuesta de texto con el código HTTP "Solicitud incorrecta". En este caso, la ejecución se detendrá aquí y no se llamará al trabajador.
Para activar esta protección para el método addUser, necesitamos agregar esto encima de addUser. El guardia se agrega usando el decorador "Guardias". Entonces agreguemos la guardia:
@Worker([HTTP_METHOD.Post])
@Route("/")
@Guards([UserValidatorGuard])
async addUser(@Singleton(UserService) service) {
    const newUser = service.addUser(this.data.user);
    return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}
En el código anterior:
  • He agregado el protector, "UserValidatorGuard" utilizando los decoradores Guards.
  • Con la guardia en el proceso, ya no necesitamos analizar los datos del cuerpo dentro del trabajador. Más bien, lo estamos leyendo de this.data que estamos pasando de "UserValidatorGuard".
  • El método "addUser" solo se llamará cuando Guard lo permita, lo que significa que todos los datos son válidos.
Una cosa a tener en cuenta es que el método "addUser" se ve muy ligero después de usar un componente, y también está validando. Puede agregar múltiples protectores a un trabajador, lo que le brinda la capacidad de modularizar su código en múltiples protectores y usar ese protector en múltiples lugares.
¿No es genial: D?
Intentemos agregar un usuario con algunos datos no válidos:
Como puede ver en la captura de pantalla, he intentado enviar una solicitud sin contraseña. El resultado es: "la contraseña debe tener un mínimo de 5 caracteres". Por lo tanto, significa que el protector está activado y funciona perfectamente.

PONER

Agreguemos otro método: "updateUser" con la ruta "/", proteja "UserValidatorGuard" (para la validación del usuario) y lo más importante: trabajador con el método http "PUT".
@Worker([HTTP_METHOD.Put])
@Guards([UserValidatorGuard])
@Route("/")
async updateUser(@Singleton(UserService) service) {
    const user = this.data.user;
    const userUpdated = service.updateUser(user);
    if (userUpdated === true) {
        return textResult("user updated");
    } else {
        return textResult("invalid user");
    }
}
El código actualizado es similar al código addUser, excepto que, en lo que respecta a la funcionalidad, está actualizando los datos. Aquí, hemos reutilizado UserValidatorGuard para validar los datos.

ELIMINAR

Para eliminar datos, el usuario debe pasar la identificación del usuario. Esto puede ser pasado por:
  • Enviando datos en el cuerpo como lo hicimos para agregar y actualizar - {id: 1}
  • Envío de datos en cadena de consulta -? Id = 1
  • Envío de datos en ruta: para esto, necesitamos personalizar nuestra ruta: "/ user / 1"
Ya hemos implementado la obtención de datos del cuerpo. Así que veamos otras dos formas:
Envío de datos en cadena de consulta
Creemos un método "removeByQueryString" y peguemos el siguiente código:
@Worker([HTTP_METHOD.Delete])
@Route("/")
async removeByQueryString(@Singleton(UserService) service) {
    // taking id from query string
    const userId = Number(this.query.id);
    const user = service.getUser(userId);
    if (user != null) {
        service.removeUser(userId);
        return textResult("user deleted");
    } else {
        return textResult("invalid user", 404);
    }
}
Envío de datos en ruta
Puede parametrizar la ruta utilizando "{var}" en una ruta. A ver cómo.
Creemos otro método "removeByRoute" y pegue el siguiente código:
@Worker([HTTP_METHOD.Delete])
@Route("/{id}")
async removeByRoute(@Singleton(UserService) service) {
    
    // taking id from route
    const userId = Number(this.param.id);

    const user = service.getUser(userId);
    if (user != null) {
        service.removeUser(userId);
        return textResult("user deleted");
    } else {
        return textResult("invalid user");
    }
}
El código anterior es exactamente el mismo que removeByQueryString, excepto que está extrayendo la identificación de la ruta y está usando el parámetro en la ruta, es decir, "/ {id}" donde id es el parámetro.
Probemos esto:
Por lo tanto, finalmente hemos creado una API REST para todas las funciones, excepto OBTENER un usuario en particular por id. Te lo dejaré para practicar.

PUNTOS DE INTERÉS

P: ¿Cómo agregamos la autenticación a "UserController", de modo que cualquier solicitud no autenticada no pueda llamar al punto final "/ user".
A: Existen múltiples enfoques para esto:
  • Podemos verificar la autenticación de cada trabajador. (MALO - tanto trabajo extra y repetición de código)
  • Cree un componente de Guardia y asígnelo a cada trabajador. (BUENO)
  • Cree un componente Shield y asígnelo al controlador. El escudo es una capa de seguridad similar al protector, pero funciona encima del controlador, por lo que si el escudo rechaza, el controlador no se inicia. (MEJOR)
Eche un vistazo a los documentos de autenticación de FortJs: http://fortjs.info/tutorial/authentication/

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

Post Top Ad

Your Ad Spot

Páginas