Aplicación Web Ecommerce

Aplicación Web Ecommerce - Ing. Gary Guzmán

©️ Por: Ing. Gary Guzmán

👨‍💻 Repositorio mis resúmenes por @garyDav

🗓️ Publicado, 01 de abril del 2022


Ramas en git

Estando en la rama master.

git add .
git commit -m "new rama"
git checkout -b newRama
git push origin newRama
git checkout master
git push origin master

git checkout newRama
git merge master

01BasicStructure

Estructura básica de un proyecto en NodeJS, Express, Template engine (Pug) y MongoDB.

Comandos:

mkdir ecommerce
cd ecommerce
npm init -y
npm i -S express
npm i -S pug
npm i -D nodemon

Archivos añadidos:

  • package.json
  • index.js
  • .gitignore
  • avance.md

Archivos acualizados:

  • index.js
  • package.json

02PugTemplateEngine

Usando Pug como Template Engine.

Archivos añadidos:

  • ./routes/products.js
  • ./views/products.pug

Archivos acualizados:

  • index.js

03ImplementBulmaInPug

Implementando el framework Bulma en el Template Engine “Pug”.

Bulma solo tiene CSS, lo que lo hace muy liviano a comparación de Bootstrap.

Archivos añadidos:

  • ./views/footer.pug
  • ./views/navbar.pug
  • ./views/layout.pug

Archivos acualizados:

  • ./views/products.pug

04StaticFiles

Implementando archivos estáticos.

Archivos añadidos:

  • ./public/assets/main.css
  • ./public/images/hero-bg.jpg
  • ./public/logo/octolion-white@2x.png
  • ./public/logo/octolion@2x.png
  • ./public/favicon.png

Archivos acualizados:

  • index.js
  • ./views/layout.pug
  • ./views/products.pug
  • ./views/footer.pug
  • ./views/navbar.pug

05API_REST-FULL

Implementando la anatomía para una API REST-FULL.

REST, estilo de arquitectura para Web services, no es un estandar pero si existe una especificación por Roy Fielding cofundador de Apache, HTTP Server y el director de Apache Software Fundation, y actualmente trabaja para Abode. Consiste en el envío y recivimiento de archivos json y XML, utiliza HTTP Verbs explícitamente (GET, POST, DELETE, etc…), también tiene un patrón de URI y está basado en directorios para las rutas.

HTTP Verbs

API Verbs

Archivos añadidos:

  • ./routes/api/products.js
  • ./utils/mocks/products.js

Archivos acualizados:

  • index.js
  • ./routes/products.js

06ServiceLayer

Implementando capa de servicio.

Veremos una aquitectura que está basado en MVC.

La arquitectura MVC se quedó corto, autores como Taylor Otwell creador de Laravel, habla de que no es suficiente, MVC debería ser llamado: Separación de Problemas.

Nuestro “Modelo” es parte del paquete “Librerías”, este paquete es básicamente el que se encarga de conectarse con librerías externas, es decir: Base de datos, Base de datos de otros servicios, y otras APIs. La “Vista” realmente está representada por los datos que enviamos o recivimos que nos envía el “Controlador”, la función de este “Controlador” es simplemente recivir y enviar datos a la “Vista”. En éste caso nuestro “Controlador” está representado por los Middlewares y Router que implementamos, este “Controlador” también se encargan de las API que en este caso reciven y envían JSON. Y los Servicios es el corazón de nuestra aplicación, los servicios se encargan, no solo de llamar a las “Librerías”, si no llamar a otros Servicios, básicamente la Lógica de Negocios centra en esta parte.

Explicando el flujo: Sea que reciva una llamada por una View o un API el Controllers recive ésta información y su única tarea es pasarle ésta información a los Services, éstos Servicios deciden que hacer con esto, ya sea llamar a ótros Servicios, si van aplicar una Logica de Negocios, si van aplicar Reglas de Seguridad, etc., y cuándo yá tengan claro eso, ésos Servicios llaman a las Libraries (Lib), la lógica que deberían tener las Librerías es exclusívamente para el consumo de Datos, puede que llame a las Librerías de MongoDB, en Firebase, ó para llamar a otra API que séa posible. Ésto es básicamente la arquitectura.

Capas MVC

Comandos:

npm i -S body-parser

Para desinstalar una librería de nuestro package.json.

npm uninstall -S body-parse

Archivos añadidos:

  • ./services/products.js

Archivos acualizados:

  • ./routes/api/products.js
  • ./routes/products.js
  • index.js

07RecappingTheProject

Recapitulando el proyecto, cambiamos la estructura del proyecto y añadimos comentarios.

Archivos acualizados:

  • index.js
  • ./routes/views/products.js
  • ./routes/api/products.js

08MongoDBconnectionExpress

Cómo conectarse a una instancia de MongoDB usando mLab, es un servicio de base de datos que nos ofrece conexiones a MongoDB, para ello lo que tenemos que hacer es:

  • Crear una Cuenta.
  • Crear una Base de Datos.
  • Crear un usuario.

Es importante que las credenciales de la cuenta de mLab las creemos usando aplicativos como LastPass o 1Password.

Es importante que nuestro archivo .env no exista en nuestro repositorio de github, porque ahí tendremos toda la información necesaria, para conectarnos a nuestra BD.

Actualmente mlab es parte de MongoDB, así que con nuestras credenciales ya creadas accedemos a mongodb.com, una vez dentro creamos un Cluster gratuino, cambiamos el nombre Cluster0 por cualquiera, en mi caso será ggary.

Configurando nuestro Cluster

  1. Crear usuario, en la parte del menú, accedemos a Security->Database Access, agregamos un nuevo usuario de la BD, en mi caso el usuario es mgary, estas credenciales lo usaremos en el archivo .env.

  2. IP Address, en la parte del menú, accedemos a Security->Network Access, añadimos un IP Address, pulsamos ADD CURRENT IP ADDRESS, nos genera una IP 0.0.0.0/0, por medio de esta lista de IP Addresses accedemos a nuestro Cluster.

  3. BD, en la parte del menú, accedemos a Atlas->Clusters, nos aparecerá una lista de nuestros Clusters, en la que creamos precionamos COLLECTIONS, y creamos nuestra base de datos, para este proyecto será octolion, con la colección products.

Conectarse a nuestra BD del Cluster

  • Conectarse por mongo shell, en mi caso la versión 4.2.5.

shell-1

shell-2

shell-3

Mi cadena de coneccción: mongo "mongodb+srv://ggary-dy8z2.mongodb.net/test" --username mgary.

shell-4

Ingresamos la contraseña de nuestro usuario de la BD.

shell-5

Mostramos las BD.

shell-6

  • Conectarse por Studio 3T:

studio-0

studio-1

studio-2

Al copiar la cadena de conección: mongodb+srv://mgary:<password>@ggary-dy8z2.mongodb.net/test.

Añadimos la contraseña del usuario ggary y pegamos en Studio 3T: New Connection->From URI....

studio-3

studio-4

studio-5

No olvidemos cambiar por la contraseña correcta.

studio-6

studio-7

Todos estos datos anteriores debería hallar por defecto, una vez terminado, precionamos en Test Connection para asegurarnos que la conección tiene éxito.

studio-8

studio-9

Como la conección fue exitosa nos muestra las BD de nuestro Cloud.

studio-10

  • Conectarse por Robo 3T:

robo-1

robo-2

Editamos Name, en nuestro caso pondré Octolion.

robo-3

robo-4

robo-5

  • Conectarse por MongoDB Compass:

compass-1

No olvidemos cambiar la contraseña.

compass-2


09ServicesWithMongoDB

Creamos un archivo de configuración .env.example para que el desarrollador cree su propio archivo .env lo cual no debe ser añadido al repositorio, luego realizamos la conección a nuestro mongoDB de nuestro Cloud, por último comprobamos listando la colección de products.

Comandos:

npm i -S dotenv
npm i -S mongodb

Archivos añadidos:

  • ./.env.example
  • ./.env
  • ./config/index.js
  • ./lig/mongo.js

Archivos acualizados:

  • ./avance.md
  • ./.gitignore
  • ./services/products.js

10ImplementingCRUD

Implementamos acciones CRUD de mongo DB y lo utilizamos en nuetro servicio, para realizar la prueba utilizamos postman.

CRUD-MongoDB

Archivos acualizados:

  • ./avance.md
  • ./lib/mongo.js
  • ./services/products.js

11Middleware

Es nada más una función, que tiene tiene tres argumentos:

  • El request object
  • El response object
  • Y un Callback llamado next, que cuando se invoca llama al siguiente middleware.

Piensen en un middleware como una serie de capas en un request.

¿Para que sirve?

Para hacer modificaciones al request y al response object, podemos hacer cosas como validaciones, manejo de errores, etc…

Pero lo más importante del middleware es, siempre llamar a la función next()

Middleware

Tipos de Middleware

Middleware

Ejemplos de cada uno, respectivamente.

  • Body-parser: cuando lo agregamos a nuestra aplicación, lo que hace es: interceptar el request verificar que tenga un cuerpo (Body) y si necesita ser formateado a json, y aplicar lo necesario para que funcione.

  • Router aplicadas a nuestras API o a nuestras Vistas “routes/api” “routes/views”.

  • Express-static, por que se usa con app.use().

  • Integrados con Express.

  • Lo veremos en el siguiente apartado.

Archivos acualizados:

  • ./avance.md

12ErrorsWithMiddlewares

Las mejores formas de manejar errores en express es usando un middleware.

ErrorMiddleware

Archivos añadidos:

  • ./utils/middlewares/errorsHandlers.js
  • ./views/error.pug

Archivos acualizados:

  • ./avance.md
  • ./routes/api/products.js
  • ./routes/views/products.js
  • ./index.js

13ValidationWithMiddlewares

Evitamos que nos envíen a nuestros EndPoints datos que no corresponden al esquema que tenemos.

Implementaremos una función de tipo Clusure.

FunctionClosure

El schema es simplemente las reglas, de como deben ser nuestros datos, como el tipo de dato en un campo o si es requerido, o no, etc.

En check diremos que parte del request vamos a validar, por defecto es body.

Luego veremos como utilizar joi para nuestro middleware de validación, y como utilizar boom para nuestros middlewares de errores.

Archivos acualizados:

  • ./avance.md

14JoiAndBoom

Son librerías que vienen del ecosistema de HapiJS.

Joi, es básicamente un validador de esquemas de objetos.

Boom, nos permite enviar errores de una manera más agradable.

Una vez implementado joi realizamos pruebas:

Validation-POST-Postman

Validation-PUT-ID-Postman

Comandos:

npm i -S joi
npm i -S boom

Archivos añadidos:

  • joi ./utils/schemas/products.js
  • boom ./utils/isRequestAjaxOrAPI.js
  • boom ./views/404.pug

Archivos acualizados:

  • ./avance.md
  • joi ./utils/middlewares/validationHandler.js
  • joi ./routes/api/products.js
  • boom ./utils/middlewares/errorsHandlers.js
  • boom ./utils/middlewares/validationHandler.js
  • boom ./index.js
  • boom ./views/error.pug

15Authentication

Implementamos nuestro access_token

Para ejecutarlo en Postman accedemos al apartado -> Auth -> TYPE “Basic Auth” -> username: admin -> Password: ******

POST token

Podemos comprobar nuestro access_token vamos a la página https://jwt.io/

JWT.IO

JSON Web Tokens

Es un estándar que nos permite representar claims (reclamaciones), que podría ser traducido como peticiones o permisos entre dos partes, un JSON Web token tiene las siguientes partes:

JWT

El Header lo que incluye, cuál fue el algoritmo con el que se firmó y si el tipo de token es JSON Web token.

El Payload normalmente tiene información que queremos compartir entre esas partes, éstos son los claims, sub generalmente hace parte a la identificación del usuario, debemos tener mucho cuidado de no incluir información sencible, porque esto puede ser facilmente decodificado, iat es cuándo se genero el token “el tiempo”.

El Signature (firma), generalmente se hace codificando el Header concatenando con un punto, más el payload y firmándolo con nuestro string secreto.

Si por alguna razón cambian el payload o cambian el header, para simular un token con permisos extras, como la firma siempre estará contruida basada en el header y el payload, dará invalido.

Asegurando nuestra API con JWTs

Para esto debemos crear una nueva estrategia utils->auth->strategies->jwt.js, por medio de este archivo comprobaremos si el JWT está bien firmado, y obtendremos la información del usuario de él.

Luego nos toca incluir ésta estrategia en nuestro end-point, para así asegurar nuestras rutas de actualizar producto y eliminar.

Unauthorized

Access Token

Authorizarion

Comandos:

npm i -S passport passport-http passport-jwt jsonwebtoken bcrypt
npm i -D chalk

Archivos añadidos:

  • ./scripts/mongo/seed-admin.js

  • ./utils/auth/strategies/basic.js

  • ./routes/api/auth.js

  • ./utils/auth/strategies/jwt.js

Archivos acualizados:

  • ./.env.example

  • ./.env

  • ./config/index.js

  • ./index.js

  • ./routes/api/products.js


16Test

Cuando hacemos el llamado de las rutas, y las agregamos a nuestra aplicación, estamos diciendo practicamente a nuestra aplicación que rutas usar, en la inversión de control que aplicaremos, consiste en que la ruta decide qué aplicación usar.

El siguiente paso es crear una utilidad para levantar un servidor de pruebas, donde implementamos la inversión de control.

Luego empezamos a crear nuestras sentencias de test, creamos una ruta que estará intervenida con proxyquire, para la ruta de servicio lo remplazamos por Mock, lo que queremos probar es que los controladores (reciben y envían datos) den correctamente.

El paso siguiente es probar los servicios, y de igual manera como hicimos para probar los end-points tuvimos que hacer Mock para nuestros servicios, los servicios que llaman a nuestras librerías, éstas tienen que ser Mockeadas.

Para hacer estos Mock y los llamados, usaremos la librería sinon, nos permite hacer Mocks, stub’s y una serie de cosas que pueden encontrar en la página de sinon.

Con nuestro getAllStub.withArgs() cuando se le pase ciertos argumentos retorne ciertas cosas.

Comandos:

npm i -D supertest mocha sinon proxyquire

Archivos añadidos:

  • ./test
  • ./utils/testServer.js
  • ./test/routes.api.products.test.js
  • ./utils/mocks/mongoLib.js
  • ./test/services.products.test.js
  • ./test/utils.isRequestAjaxOrApi.test.js

Archivos acualizados:

  • ./package.json
  • ./routes/api/products.js
  • ./index.js
  • ./utils/mocks/products.js

17Debuggin-Inspect

Debug nos muestra en consola el mensaje de nuestro work space, con colores e incluso el tiempo que demora.

Inspect en nuestro navegador abrimos el google developer tools y nos aparece el ícono de node, precionamos, nos habre una nueva ventana, precionamos Sources y podemos crear puntos de interrupción y poder depurar nuestro código.

Comandos:

npm i -S debug

Archivos añadidos:

Archivos acualizados:

  • ./package.json
  • ./index.js
  • ./lib/mongo.js
  • ./utils/middlewares/errorsHandlers.js

18GoodPractices

Middlewares populares

  • body-parser
  • cors
  • morgan
  • helmet
  • express-debug
  • express-slash
  • passport
body-parser:

No solo nos permite transformar body a tipo json, tambén recibe row, puede ser un buffer, un binario, también recibe texto y url encode.

cors:

Nos sirve para verificar los request, que hace un cliente desde un navegador, sea del mismo dominio ó que permitamos a todos. Esto es por temas de seguridad, para evitar que nos hagan request desde clientes que no pertenecen al mismo dominio, es una muy buena practica activar el cors en el mismo dominio, ó dominios que sabemos que van a consumir nuestros end-points para producción.

morgan:

Es un loguer de request, si por ejemplo, queremos hacer un console.log(req) de nuestro objeto request para explorar que tiene, ya nó sería necesario hacerlo, instalando morgan podemos hacer esto automaticamente.

helmet: