Skip to content

Node App | [7] Middlewares

Ian Basly edited this page Nov 1, 2020 · 1 revision

Versión: 1.0.0

El desarrollo de este material sigue la línea de desarrollo de las cápsulas anteriores App Node [4]. El material en que se basa se encuentra disponible en este repositorio, específicamente en la ruta material/carrito+mws.

Para una correcta explicación del contenido visto y aplicado en esta cápsula, se hicieron las siguientes modificaciones al material base.

Configuraciones 🛠️

Primero es necesario definir las variables de entorno

DB_USERNAME=postgres
DB_PASSWORD=password
DB_NAME=carrito
DB_HOST=localhost

Luego se debe crear la base de datos para alojar el proyecto. Para esto es necesario correr los siguientes comandos:

npm install
npx sequelize db:create

Para correr el proyecto por primera vez es necesario ejecutar las migraciones:

npx sequelize db:migrate
npx sequelize db:seed:all

Luego, para levantar la aplicación se debe ejecutar:

npm start

Instalación de dependencias extras 📚

Para el correcto funcionamiento del proyecto se instalaron las siguientes dependencias:

dotenv // leer variables de entorno
bcrypt // hashear contraseñas
jsonwebtoken // identificador de usuario único a ser usado en cada request 

Migraciones ⬇️

Directorio: /migrations

Se agregaron migraciones para incorporar password y token para el customer. Además se agregó un stock para los products. Finalmente se corrigió la asociación entre órdenes y productos, ya que un producto puede estar presente en varias órdenes y una orden se compone de varios productos (relación N:M). Para ello se agregó la tabla intermedia products_order la cual tiene como columnas productId y orderId.

Modelos 🎭

Directorio: /models

Se agregaron los atributos extras mencionados en el apartado anterior a customer y orders. Además de la asociación entre orders y products a través de la tabla products_order.

Seeds 🌱

Directorio: /seeders

Se actualizaron las seeds de customers y products en base a lo mencionado anteriormente.

Middlewares ➡️ 🎛️ ➡️

Directorio: /middlewares

Recordar que los middlewares son programas que nos ayudan a separar las reponsabilidades de los controladores (routes) y evitar repetir código de manera excesiva. Estos programas actuan de forma intermediaria al flujo normal, donde una consulta pasa primero por un middleware, desde donde puede ser pasar por varios hasta llegar al controlador mismo. El mejor ejemplo (y visto en la cápsula) es la autentificación de un usuario antes de continuar con la función de una ruta en cuestión.

Se agregaron 3 archivos de middlewares, para auth, customer y orders. A continuación se detalla la finalidad de cada uno.

Auth Middleware

Directorio: /middlewares/auth.js

Este middleware se encarga de revisar que exista un token en el Header de la request. En caso de existir el token, busca al usuario con ese token y lo agrega al ctx, de modo que ya no es necesario volver a consultar a la base de datos por el currentCustomer. En caso de que no exista el token o que no haya un cliente con ese token asociado, se retorna un mensaje de error.

Customer Middleware

Directorio: /middlewares/customers.js

Dentro de este archivo se encuentra un tipo especial de middleware llamado customerGuard que se encarga de proteger un recurso (se aplica a las rutas de /customers que requieren un :id). La idea es proteger el recurso y solo si el currentCustomer tiene el mismo id que el customer a ver o modificar se permita la acción.

Orders Middlewares

Directorio: /middleware/orders.js

Dentro de este directorio, podemos encontrar dos middlewares, los cuales ayudan a procesar las solicitudes de órdenes.

  • orderGuard Es el primer middleware, el cual se encarga de validar que la :id ingresada en la ruta corresponda a una orden válida y a su vez que esta orden sea del usuario que está realizando la consulta. En caso de que lo anterior se cumpla, entonces la orden a la cual se está ingresando quedará referenciada en la variable currentOrder del contexto (ctx). En caso contrario se retornará el mensaje de error correspondiente.

  • validateStock Por otro lado este middleware se encarga de validar que aún exista stock suficiente para agregar el producto a la orden, en caso de que alguno de los productos no cuenten con stock, se responderá con el error indicando que productos no están disponibles. (Ver sección Endpoint).

Endpoints 🌐

Para la relizar la gran mayoría de las consultas es necesario haber iniciado sesión, a lo cual se recibirá un token que debe ser utilizado para cada consulta que requiera autentificación.

Sin autentificación

  • Log In POST /auth/login

    {
      "email": "algun@email.com",
      "password": "constraseña"
    }

    Responses:

     //Good request
     {
       "msg": "Has iniciado sesión correctamente",
       "token": "TOKEN_SESION"
     }
     
     //Bad request
     {
       "error": "Credenciales inválidas"
     }
  • Nuevo Cliente POST /costumer/new

    {
      "name": "Juan Perez",
      "email": "juan@mail.com",
      "password": "password",
    }

Con autentificación (Bearer Authentication)

Para las siguientes consultas, es necesario haber iniciado sesión con el endpoint señalado anteriormente y disponer de un token (Bearer token), el cual debe ir en el Header Authorization. Ej: Authorization: "Bearer {TOKEN_SESION}" Donde {TOKEN_SESION} es el token provisto.

  • Log out DELETE auth/logout

    Responses:

    //Good Request
    {
      "msg": "Se ha cerrado sesión correctamente"
    }
    
    //Bad Request
    {
      "error": "Debe iniciar sesión"
    }
  • Nueva Orden POST /orders/new

     {
       "name": "Nueva Orden",
       "description": "Esta es una nueva orden"
     }

    Response:

    //Good Request
    {
      "id": X,
      "name": "Nueva Orden",
      "description": "Esta es una nueva orden"
    }
    
    //Bad Request
    {
      "error": "Debes iniciar sesión"
    }
  • Agregar Productos POST /orders/:id/add

    {
      "products": [
        1,
        2
        ...
      ]
    }

    Response:

    //Good Request
    {
      "order": {
      	"id": 0,
      	"name": "Esta es la Orden 0",
      	"description": "Esta es una orden"
      },
      "products": [
        {
      	  "id": 1,
      	  "name": "Producto 1",
      	  "description": "Esta es la descripción de un producto",
      	  "price": 100,
      	  "stock": 1
        },
        {
      	  "id": 2,
      	  "name": "Producto 2",
      	  "description": "Esta es la descripción de un producto",
      	  "price": 100,
      	  "stock": 1
        },
      ]
    }
    
    //Bad Request
    {
      "error": "No se ha podido crear la orden algunos productos no tienen suficiente stock",
      "declinedProducts": [
        5
      ],
    }
  • Products GET /products

    Response:

     {
       "products": [
         {
           "id": 1,
           "name": "Producto 1",
           "description": "Esta es la descripción de un producto",
           "price": 100,
           "stock": 1
         },
        {
           "id": 2,
           "name": "Producto 2",
           "description": "Esta es la descripción de un producto",
           "price": 100,
           "stock": 1
         },
        {
           "id": 3,
           "name": "Producto 3",
           "description": "Esta es la descripción de un producto",
           "price": 100,
           "stock": 1
         },
         ...
       ]
     }
  • Customers GET /customers/:id

    Response:

     {
       "id": 1,
       "name": "Juan",
       "email": "j@uc.cl",
       "password": "HASHED_PASSWORD",
       "token": "SECRET_TOKEN",
       "createdAt": "2020-11-01T17:54:46.263Z",
       "updatedAt": "2020-11-01T17:54:59.525Z"
     }

    PATCH /customers/:id

     {
       "name": "NEW_NAME",
       "email": "NEW_EMAIL",
     }

    Response:

     {
       "id": 1,
       "name": "NEW_NAME",
       "email": "NEW_EMAIL",
       "password": "HASHED_PASSWORD",
       "token": "SECRET_TOKEN",
       "createdAt": "2020-11-01T17:54:46.263Z",
       "updatedAt": "2020-11-01T17:54:59.525Z"
     }

    DELETE /customers/:id

    Response:

     {
       "msg": "Cliente eliminado correctamente"
     }

Sitios recomendados 💡