From e918faf1ed2d0928fc8c488d2cbfbb50efc0fe33 Mon Sep 17 00:00:00 2001 From: Ivy Feraco Date: Wed, 17 May 2023 09:39:52 -0500 Subject: [PATCH] refactor(content): bq api - codigo necesario por mongoDB setup, mover docker reqs, fix spawn en Windows (#1353) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * trabajo necesario por mongoDB setup y spawn en Windows * cambios a README * ideas para adiciones GETTING_STARTED * comentando config y e2e tests mejor * mdlint fixes * separating docker and mongo guides * remove mongo deps from package.json * clean mongoDB references de proyecto * patch for Mongo * Update projects/04-burger-queen-api/README.md * cambios al readme y guia * mdlint fixes * readd jsonwebtoken dep * remove ws from patch * patch in the wrong place * patch mongoDB created from project not from bootcamp * actualizar table of contents * update guia and remove mongoose refs * minor corrections * rehacer el patch * corrections * remove redundant checklist, node driver resource * Update TODO projects/04-burger-queen-api/controller/users.js Co-authored-by: Alfredo González <12631491+mfdebian@users.noreply.github.com> * mas detalle en TODO comentarios * quitar mysql postgres de readme inicial, hacker edition docker * apply and remove patch for e2e tests * linter and section for hacker edition * Apply grammar and spelling suggestions from code review Co-authored-by: Mariano Crowe * remove MySQL and add code link for snippet * mas correciones de spelling, con uso de extension * Update auth.js * Apply suggestions from code review * update pt README * translations in pt, editions of docker readme * borra parte 1 de docker, es redundante * mdlint fixes * cambios de connect y TODOs * agregamos status de resp en globalSetup errors * Update projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.md Co-authored-by: Alfredo González <12631491+mfdebian@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Alfredo González <12631491+mfdebian@users.noreply.github.com> * espanol no pt, error response * Update README.md guides url * Update README.pt.md url guides y texto duplicado --------- Co-authored-by: Alfredo González <12631491+mfdebian@users.noreply.github.com> Co-authored-by: Mariano Crowe --- projects/04-burger-queen-api/README.md | 132 +++---- projects/04-burger-queen-api/README.pt.md | 134 +++---- projects/04-burger-queen-api/config.js | 2 +- projects/04-burger-queen-api/connect.js | 10 + .../04-burger-queen-api/controller/users.js | 1 + .../04-burger-queen-api/e2e/globalSetup.js | 77 ++-- .../GETTING-STARTED-DOCKER.md} | 171 +-------- .../guides/GETTING-STARTED-DOCKER.pt.md | 348 ++++++++++++++++++ .../guides/GETTING-STARTED-MONGODB.md | 268 ++++++++++++++ .../guides/GETTING-STARTED-MONGODB.pt.md | 261 +++++++++++++ projects/04-burger-queen-api/index.js | 4 +- .../jest-mongodb-config.js | 15 + projects/04-burger-queen-api/package.json | 4 +- projects/04-burger-queen-api/routes/auth.js | 4 + projects/04-burger-queen-api/routes/users.js | 5 + 15 files changed, 1073 insertions(+), 363 deletions(-) create mode 100644 projects/04-burger-queen-api/connect.js rename projects/04-burger-queen-api/{GETTING-STARTED.md => guides/GETTING-STARTED-DOCKER.md} (61%) create mode 100644 projects/04-burger-queen-api/guides/GETTING-STARTED-DOCKER.pt.md create mode 100644 projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.md create mode 100644 projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.pt.md create mode 100644 projects/04-burger-queen-api/jest-mongodb-config.js diff --git a/projects/04-burger-queen-api/README.md b/projects/04-burger-queen-api/README.md index d8443c913..b61100c0d 100644 --- a/projects/04-burger-queen-api/README.md +++ b/projects/04-burger-queen-api/README.md @@ -7,8 +7,8 @@ * [3. Objetivos de aprendizaje](#3-objetivos-de-aprendizaje) * [4. Consideraciones generales](#4-consideraciones-generales) * [5. Criterios de aceptación mínimos del proyecto](#5-criterios-de-aceptaci%C3%B3n-m%C3%ADnimos-del-proyecto) -* [6. Pistas, tips y lecturas complementarias](#6-pistas-tips-y-lecturas-complementarias) -* [7 HTTP API Checklist](#7-http-api-checklist) +* [6. Hacker (Devops) Edition con Docker](#6-hacker-%28devops%29-edition-con-docker) +* [7. Pistas, tips y lecturas complementarias](#6-pistas-tips-y-lecturas-complementarias) ## 1. Preámbulo @@ -44,8 +44,8 @@ _endpoints_ (puntos de conexión o URLs) y nos piden completar la aplicación. Esto implica que tendremos que partir por leer la implementación existente, y familiarizarnos con el _stack_ elegido ([Node.js](https://nodejs.org/) y [Express](https://expressjs.com/)) y complementarlo con un motor de bases de -datos, el cual tu deberás elegir entre [MongoDB](https://www.mongodb.com/), -[PostgreSQL](https://www.postgresql.org/) y [MySQL](https://www.mysql.com/). +datos. Recomendamos el uso de [MongoDB](https://www.mongodb.com/) y tenemos una +[guía para empezar con MongoDB](./guides/GETTING-STARTED-MONGO-DB.md). La clienta nos ha dado un [link a la documentación](https://app.swaggerhub.com/apis-docs/ssinuco/BurgerQueenAPI/2.0.0) que especifica el comportamiento esperado de la API que expondremos por @@ -55,8 +55,7 @@ implementar la aplicación, qué parámetros esperan, qué deben responder, etc. El objetivo principal de aprendizaje es adquirir experiencia con **Node.js** como herramienta para desarrollar _aplicaciones de servidor_, junto con una serie de herramientas comunes usadas en este tipo de contexto (Express como -framework, MongoDB, PostgreSQL o MySQL como base datos, contenedores de docker, -etc). +framework, MongoDB como base datos, etc). En este proyecto tendrás que construir un servidor web que debe _servir_ `JSON` sobre `HTTP`, y desplegarlo en un servidor en la nube. @@ -64,12 +63,12 @@ sobre `HTTP`, y desplegarlo en un servidor en la nube. Para completar el proyecto tendrás que familiarizarte con conceptos como **rutas** (_routes_), **URLs**, **HTTP** y **REST** (verbs, request, response, headers, body, status codes...), **JSON**, **JWT** (_JSON Web Tokens_), -**conexión con una base datos** (`MongoDB`, `PostgreSQL`, o `MySQL`), -**variables de entorno**, **deployment**, **contenedores de `docker`**, etc. +**conexión con una base datos** (`MongoDB`), +**variables de entorno**, **deployment**, etc. ## 3. Objetivos de aprendizaje -> ℹ️ Esta sección será auomáticamente generada en el idioma pertinente, a partir +> ℹ️ Esta sección será automáticamente generada en el idioma pertinente, a partir > de los objetivos de aprendizaje declarados en [`project.yml`](./project.yml), > al crear el repo del proyecto para un cohort en particular usando > [`./scripts/create-cohort-project.js`](../../scripts#create-cohort-project-coaches). @@ -182,10 +181,10 @@ npm start 8888 Nuestra aplicación usa las siguientes variables de entorno: -* `PORT`: Si no se ha especificado un puerto como argumento de lína de comando, +* `PORT`: Si no se ha especificado un puerto como argumento de línea de comando, podemos usar la variable de entorno `PORT` para especificar el puerto. Valor por defecto `8080`. -* `DB_URL`: El _string_ de conexión de _MongoDB_ o _MySQL_. Cuando ejecutemos la +* `DB_URL`: El _string_ de conexión de _MongoDB_. Cuando ejecutemos la aplicación en nuestra computadora (en entorno de desarrollo), podemos usar el una base de datos local, pero en producción deberemos utilizar las instancias configuradas con `docker-compose` (mas sobre esto en la siguiente sección de @@ -204,107 +203,70 @@ Nuestra aplicación usa las siguientes variables de entorno: ### 5.3 Despliegue (Deployment) +Puedes elegir el proveedor (o proveedores) que prefieras junto +con el mecanismo de despliegue y estrategia de alojamiento. Te recomendamos +explorar las siguientes opciones: + +* [Vercel](https://vercel.com/) es una opción enfocada + a aplicaciones web estáticas (como las que se construyen con React). Sin embargo, + Vercel también nos permite desplegar aplicaciones node usando [Serverless + Functions](https://vercel.com/docs/serverless-functions/introduction). +* [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) + es una muy buena opción para alojar nuestra base datos de producción, la cuál + podemos usar en conjunción con cualquiera de las opciones mencionadas arriba. + +Si tienes dudas sobre las diferentes (y múltiples) opciones de despliegue no +dudes en consultar con tus pares y tus coaches. + +### 6. Hacker (Devops) Edition con Docker + Nuestra clienta nos ha manifestado que su equipo de _devops_ está siempre con -muchas tareas, por por lo que nos pide como requerimiento que la aplicación esté +muchas tareas, por lo que nos pide como requerimiento que la aplicación esté configurada con `docker-compose` para que pueda ser desplegada sin dificultades en cualquier entorno. -El _boilerplate_ ya cuenta con una configuración incial de `docker-compose` para -la aplicación de node, tu tarea será extender esa configuración para incluir la -configuración de base de datos que hayas elegido. Ten en cuenta que como vas a -tener dos servidores corriendo sobre una misma configuración, deberás exponer +El _boilerplate_ ya cuenta con una configuración inicial de `docker-compose` para +la aplicación de node, tu tarea será extender esa configuración para incluir +la configuración de base de datos. Ten en cuenta que como vas a tener dos +servidores corriendo sobre una misma configuración, deberás exponer los servicios en diferentes puertos. -Para este proyecto te recomendamos usar `docker-compose` localmente (en tu -computadora) para ejecutar la aplicación junto con la base de datos -seleccionada. Por otro lado, con respecto al despliegue, no es obligatorio usar -`docker-compose`, puedes elegir el proveedor (o proveedores) que prefieras junto -con el mecanismo de despligue y estrategia de alojamiento. Te recomendamos -explorar las siguientes opciones: +Lee la [**guía para docker**] (./guides/GETTING-STARTED-DOCKER.md) +incluido en el proyecto para mas información. + +Para probar tu configuración de docker, te recomendamos usar `docker-compose` +localmente (en tu computadora) para ejecutar la aplicación junto +con la base de datos. + +Con respecto al despliegue, puedes elegir el proveedor (o proveedores) +que prefieras junto con el mecanismo de despliegue y estrategia de alojamiento. +Te recomendamos explorar las siguientes opciones: -* [Glitch](https://glitch.com) es - probablemente la opción más _sencilla_ (la que requiere menos configuración) y - nos permite alojar el servidor web Express - importando nuestro repositorio desde GitHub. -* [Vercel](https://vercel.com/) es una opción similar a Glitch, pero enfocada - a aplicaciones web estáticas (como las que se construyen con React). Sin embargo, - Vercel también nos permite desplegar aplicaciones node usando [Serverless - Functions](https://vercel.com/docs/serverless-functions/introduction). * Si quieres explorar opciones más personalizadas y ver docker del lado del - servidor puedes cosiderar proveedores como + servidor puedes considerar proveedores como [AWS (Amazon Web Services)](https://aws.amazon.com/) o [GCP (Google Cloud Platform)](https://cloud.google.com/), ambos tienen algún tipo de _free tier_ así como tanto _instancias_ de _servidores virtuales_ (VPS) donde configurar nuestro propio Docker o servicios para desplegar aplicaciones en contenedores (por ejemplo [Compute Engine](https://cloud.google.com/compute/docs/containers) de GCP o [Elastic Container Service](https://aws.amazon.com/ecs/) de AWS). -* Si quieres trabajar con MongoDB, [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) - es una muy buena opción para alojar nuestra base datos de producción, la cuál - podemos usar en conjunción con cualquiera de las opciones mencionadas arriba. -* Si quieres trabajar con PostgreSql, [ElephantSQL](https://www.elephantsql.com/plans.html) - es una muy buena opción para alojar nuestra base datos de producción, la cuál - podemos usar en conjunción con cualquiera de las opciones mencionadas arriba. -* Si quieres trabajar con MySQL, [ClearDB](https://www.cleardb.com/) es una - muy buena opción para alojar nuestra base datos de producción, la cuál podemos - usar en conjunción con cualquiera de las opciones mencionadas arriba. -Si tienes dudas sobre las diferentes (y múltiples) opciones de despliegue no -dudes en consultar con tus pares y tus coaches. - -## 6. Pistas, tips y lecturas complementarias +## 7. Pistas, tips y lecturas complementarias ### Primeros pasos > :information_source: Antes de comenzar a programar te recomendamos leer y -> seguir con detenimiento la [**guía de _primeros pasos_**](./GETTING-STARTED.md) -> para ayudarte a elegir tu stack (base de datos, módulo para conectar a la base -> de datos desde Node.js, etc) y configurar tu entorno de desarrollo. +> seguir con detenimiento la [**guía de _primeros pasos_**](./GETTING-STARTED-MONGODB.md) +> para ayudarte con el stack recomendado y configurar tu entorno de desarrollo. ### Otros recursos * [Express](https://expressjs.com/) * [MongoDB](https://www.mongodb.com/) -* [PostgreSQL](https://www.postgresql.org/) -* [MySQL](https://www.mysql.com/) +* [MongoDB Node Driver](https://www.mongodb.com/docs/drivers/node/current/) * [docker](https://docs.docker.com/) * [docker compose](https://docs.docker.com/compose/) * [¿Qué es Docker? | Curso de Docker | Platzi Cursos](https://youtu.be/hQgvt-s-AHQ) * [Postman](https://www.getpostman.com) * [Variable de entorno - Wikipedia](https://es.wikipedia.org/wiki/Variable_de_entorno) * [`process.env` - Node.js docs](https://nodejs.org/api/process.html#process_process_env) - ---- - -## 7 HTTP API Checklist - -### 7.1 `/` - -* [ ] `GET /` - -### 7.2 `/auth` - -* [ ] `POST /auth` - -### 7.3 `/users` - -* [ ] `GET /users` -* [ ] `GET /users/:uid` -* [ ] `POST /users` -* [ ] `PATCH /users/:uid` -* [ ] `DELETE /users/:uid` - -### 7.4 `/products` - -* [ ] `GET /products` -* [ ] `GET /products/:productid` -* [ ] `POST /products` -* [ ] `PATCH /products/:productid` -* [ ] `DELETE /products/:productid` - -### 7.5 `/orders` - -* [ ] `GET /orders` -* [ ] `GET /orders/:orderId` -* [ ] `POST /orders` -* [ ] `PATCH /orders/:orderId` -* [ ] `DELETE /orders/:orderId` diff --git a/projects/04-burger-queen-api/README.pt.md b/projects/04-burger-queen-api/README.pt.md index 283fa559b..74e6bc8d5 100644 --- a/projects/04-burger-queen-api/README.pt.md +++ b/projects/04-burger-queen-api/README.pt.md @@ -7,8 +7,8 @@ * [3. Objetivos de aprendizagem](#3-objetivos-de-aprendizagem) * [4. Considerações gerais](#4-considerações-gerais) * [5. Critérios de aceitação mínimos do projeto](#5-critérios-de-aceitação-mínimos-do-projeto) -* [6. Pistas, tips e leituras complementares](#6-pistas-tips-e-leituras-complementares) -* [7 HTTP API Checklist](#7-http-api-checklist) +* [6. Hacker (Devops) Edition con Docker](#6-edição-hacker-devops-com-docker) +* [7. Pistas, tips e leituras complementares](#7-pistas-tips-e-leituras-complementares) ## 1. Prefácio @@ -41,10 +41,13 @@ de maneira relativamente simples, tudo isso usando JavaScript! Neste projeto partimos de um _boilerplate_ que já contém uma série de _endpoints_ (pontos de conexão ou URLs) e nos pedem para completar a aplicação. -Isto implica que teremos que começar a ler a implementação existente, e -familiarizar-nos com a _stack_ escolhida ([Node.js](https://nodejs.org/) e -[Express](https://expressjs.com/)) e complementá-la com um motor de banco de dados, -no qual você deverá escolher entre [MongoDB](https://www.mongodb.com/), +Isso implica que teremos que começar lendo a implementação existente e nos +familiarizar com o _stack_ escolhido ([Node.js](https://nodejs.org/) e +[Express](https://expressjs.com/)), além de complementá-lo com um motor de +banco de dados. Recomendamos o uso do [MongoDB](https://www.mongodb.com/) +e temos [um guia para começar com o MongoDB.](./guides/GETTING-STARTED-MONGO-DB.pt.md) + +[MongoDB](https://www.mongodb.com/), [PostgreSQL](https://www.postgresql.org/) e [MySQL](https://www.mysql.com/). O cliente nos deu um @@ -56,8 +59,8 @@ implementar na aplicação, que parâmetros esperam, o que devem responder, etc. O objetivo de aprendizagem principal é adquirir experiência com o **Node.js** como ferramenta para desenvolvimento de _aplicações de servidor_, junto com uma série -de outras ferramentas comumente utilizadas nesse contexto (Express como framework, -MongoDB, PostgreSQL ou MySQL como base de dados, containers de docker, etc). +de outras ferramentas comumente utilizadas nesse contexto (Express como +framework, MongoDB como base de dados, etc.). Neste projeto, você desenvolverá um servidor web que deverá _servir_ `JSON` através de uma conexão `HTTP`, e implantá-lo em um servidor na nuvem. @@ -65,8 +68,7 @@ através de uma conexão `HTTP`, e implantá-lo em um servidor na nuvem. Ao final do projeto, você deverá estar familiarizada com conceitos como **rotas** (_routes_), **URLs**, **HTTP** (verbos, request, response, headers, body, status codes, etc), **JSON**, **JWT** (_JSON Web Tokens_), **conexão com uma base de dados** -(`MongoDB`, `PostgreSQL` ou `MySQL`), **variables de ambiente**, **deployment**, -**containers de `docker`**, etc. +(`MongoDB`), **variables de ambiente**, **deployment**, etc. ## 3. Objetivos de aprendizagem @@ -205,31 +207,45 @@ Nossa aplicação usa as seguintes variáveis de ambiente: ### 5.3 Implantação (Deployment) -Nosso cliente nos informou que a sua equipe de _devops_ está sempre com muitas -tarefas, portanto, pediu como requesito que a aplicação esteja configurada -com `docker-compose` para que possa ser implantada sem dificuldades em qualquer -ambiente. - -O _boilerplate_ já conta com uma configuração incial de `docker-compose` para -a aplicação de node, sua tarefa será estender essa configuração para incluir a -configuração do banco de dados escolhido. -Leve em consideração que como terá dois servidores rodando sobre uma mesma -configuração, deverá colocar os serviços em diferentes portas. - -Para este projeto te recomendamos a usar `docker-compose` localmente (em seu -computador) para executar a aplicação junto com a base de dados -selecionada. Por outro lado, em relação a implantação, não é obrigatório usar -`docker-compose`, você pode escolher o provedor (ou provedores) que preferir junto -com o mecanismo de implantação e estratégia de hospedagem. Te recomendamos -explorar as seguintes opcões: - -* [Glitch](https://glitch.com) é provavelmente a opção mais _simples_ -(requer menos configuração) e nos permite hospedar o servidor web Express -importando nosso repositório do GitHub. -* [Vercel](https://vercel.com/) é uma opção semelhante ao Glitch, mas -focada em aplicativos web estáticos (como os construídos com React). -No entanto, o Vercel também nos permite implantar aplicativos node usando +Você pode escolher o provedor (ou provedores) que preferir, +juntamente com o mecanismo de implantação e estratégia de hospedagem. +Recomendamos que você explore as seguintes opções: + +* [Vercel](https://vercel.com/) é uma opção focada em aplicativos +da web estáticos (como os construídos com React). No entanto, +o Vercel também nos permite implantar aplicativos node usando [Serverless Functions](https://vercel.com/docs/serverless-functions/introduction) +[MongoDB Atlas](https://www.mongodb.com/cloud/atlas) +é uma ótima opção para hospedar nosso banco de dados de produção, +que pode ser usado em conjunto com qualquer uma das opções mencionadas acima. + +Se tiver dúvidas sobre as diferentes opções de implantação (que são várias), +não hesite em consultar seus colegas e seus coaches. + +## 6. Edição Hacker (DevOps) com Docker + +Nossa cliente nos informou que sua equipe de DevOps está sempre +ocupada com muitas tarefas, portanto, ela nos pede como requisito que +o aplicativo seja configurado com `docker-compose` para que possa ser +implantado facilmente em qualquer ambiente. + +O boilerplate já possui uma configuração inicial de `docker-compose` +para o aplicativo Node.js, sua tarefa será estender essa configuração para +incluir a configuração do banco de dados. Tenha em mente que, +como você terá dois servidores sendo executados na mesma configuração, +você precisará expor os serviços em portas diferentes. + +Leia o [guia para docker](./guides/GETTING-STARTED-DOCKER.pt.md) incluído +no projeto para mais informações. + +Para testar sua configuração do Docker, recomendamos que você use o +`docker-compose` localmente (em seu computador) para executar o +aplicativo junto com o banco de dados. + +Quanto à implantação, você pode escolher o provedor (ou provedores) +que preferir, juntamente com o mecanismo de implantação e estratégia +de hospedagem. Recomendamos que você explore as seguintes opções: + * Se quiser explorar opções mais personalizadas e ver o docker do lado do servidor, pode considerar provedores como [AWS (Amazon Web Services)](https://aws.amazon.com/) ou @@ -238,60 +254,14 @@ de serviço experimental gratuito (_free tier_) assim como instâncias de servid virtuais (VPS), onde configuramos nosso próprio Docker ou serviços para implantar aplicações em contêineres (por exemplo [Compute Engine](https://cloud.google.com/compute/docs/containers) de GCP ou [Elastic Container Service](https://aws.amazon.com/ecs/) de AWS). -* Se quiser trabalhar com MongoDB, [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) -é uma opção muito boa para hospedar a base dados de produção, que -podemos usar em conjunto com qualquer uma das opções mencionadas acima. -* Se quiser trabalhar com MySQL, [ClearDB](https://www.cleardb.com/) é uma -boa opção para hospedar a base de dados de produção, que podemos usar em -conjunto com qualquer uma das opções mencionadas acima. - -Se tiver dúvidas sobre as diferentes (e múltiplas) opções de implantação, -não hesite em consultar seus colegas e mentores. -## 6. Pistas, tips e leituras complementares +## 7. Pistas, tips e leituras complementares * [Express](https://expressjs.com/) * [MongoDB](https://www.mongodb.com/) -* [PostgreSQL](https://www.postgresql.org/) -* [MySQL](https://www.mysql.com/) +* [MongoDB Node Driver](https://www.mongodb.com/docs/drivers/node/current/) * [docker](https://docs.docker.com/) * [docker compose](https://docs.docker.com/compose/) * [Postman](https://www.getpostman.com) * [Variável de ambiente - Wikipedia](https://pt.wikipedia.org/wiki/Variável_de_ambiente) * [`process.env` - Node.js docs](https://nodejs.org/api/process.html#process_process_env) - -*** - -## 7 HTTP API Checklist - -### 7.1 `/` - -* [ ] `GET /` - -### 7.2 `/auth` - -* [ ] `POST /auth` - -### 7.3 `/users` - -* [ ] `GET /users` -* [ ] `GET /users/:uid` -* [ ] `POST /users` -* [ ] `PATCH /users/:uid` -* [ ] `DELETE /users/:uid` - -### 7.4 `/products` - -* [ ] `GET /products` -* [ ] `GET /products/:productid` -* [ ] `POST /products` -* [ ] `PATCH /products/:productid` -* [ ] `DELETE /products/:productid` - -### 7.5 `/orders` - -* [ ] `GET /orders` -* [ ] `GET /orders/:orderId` -* [ ] `POST /orders` -* [ ] `PATCH /orders/:orderId` -* [ ] `DELETE /orders/:orderId` diff --git a/projects/04-burger-queen-api/config.js b/projects/04-burger-queen-api/config.js index 58b4b6e29..330d1c817 100644 --- a/projects/04-burger-queen-api/config.js +++ b/projects/04-burger-queen-api/config.js @@ -1,5 +1,5 @@ exports.port = process.argv[2] || process.env.PORT || 8080; -exports.dbUrl = process.env.DB_URL || 'mongodb://localhost:27017/test'; +exports.dbUrl = process.env.MONGO_URL || process.env.DB_URL || 'mongodb://127.0.0.1:27017/test'; exports.secret = process.env.JWT_SECRET || 'esta-es-la-api-burger-queen'; exports.adminEmail = process.env.ADMIN_EMAIL || 'admin@localhost'; exports.adminPassword = process.env.ADMIN_PASSWORD || 'changeme'; diff --git a/projects/04-burger-queen-api/connect.js b/projects/04-burger-queen-api/connect.js new file mode 100644 index 000000000..8d288c261 --- /dev/null +++ b/projects/04-burger-queen-api/connect.js @@ -0,0 +1,10 @@ +const config = require('./config'); + +// eslint-disable-next-line no-unused-vars +const { dbUrl } = config; + +async function connect() { + // TODO: Conexión a la Base de Datos +} + +module.exports = { connect }; diff --git a/projects/04-burger-queen-api/controller/users.js b/projects/04-burger-queen-api/controller/users.js index 40ecbc906..268b1fece 100644 --- a/projects/04-burger-queen-api/controller/users.js +++ b/projects/04-burger-queen-api/controller/users.js @@ -1,4 +1,5 @@ module.exports = { getUsers: (req, resp, next) => { + // TODO: Implementa la función necesaria para traer la colección `users` }, }; diff --git a/projects/04-burger-queen-api/e2e/globalSetup.js b/projects/04-burger-queen-api/e2e/globalSetup.js index 3db0e9971..1dd242ef7 100644 --- a/projects/04-burger-queen-api/e2e/globalSetup.js +++ b/projects/04-burger-queen-api/e2e/globalSetup.js @@ -1,6 +1,9 @@ const path = require('path'); const { spawn } = require('child_process'); const kill = require('tree-kill'); +const { MongoClient } = require('mongodb'); + +const mongoGlobalSetup = require("@shelf/jest-mongodb/lib/setup"); const config = require('../config'); @@ -58,13 +61,13 @@ const createTestUser = () => fetchAsAdmin('/users', { }) .then((resp) => { if (resp.status !== 200) { - throw new Error('Could not create test user'); + throw new Error(`Error: Could not create test user - response ${resp.status}`); } return fetch('/auth', { method: 'POST', body: __e2e.testUserCredentials }); }) .then((resp) => { if (resp.status !== 200) { - throw new Error('Could not authenticate test user'); + throw new Error(`Error: Could not authenticate test user - response ${resp.status}`); } return resp.json(); }) @@ -76,7 +79,7 @@ const checkAdminCredentials = () => fetch('/auth', { }) .then((resp) => { if (resp.status !== 200) { - throw new Error('Could not authenticate as admin user'); + throw new Error(`Error: Could not authenticate as admin user - response ${resp.status}`); } return resp.json(); @@ -85,7 +88,7 @@ const checkAdminCredentials = () => fetch('/auth', { const waitForServerToBeReady = (retries = 10) => new Promise((resolve, reject) => { if (!retries) { - return reject(new Error('Server took to long to start')); + return reject(new Error('Server took too long to start')); } setTimeout(() => { @@ -105,41 +108,47 @@ module.exports = () => new Promise((resolve, reject) => { return resolve(); } - // TODO: Configurar DB de tests + mongoGlobalSetup({rootDir: __dirname}).then(async () => { - console.info('Staring local server...'); - const child = spawn('npm', ['start', process.env.PORT || 8888], { - cwd: path.resolve(__dirname, '../'), - stdio: ['ignore', 'pipe', 'pipe'], - }); + console.info('\n Starting local server...'); - Object.assign(__e2e, { childProcessPid: child.pid }); + const child = spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['start', port], + { + cwd: path.resolve(__dirname, "../"), + stdio: ["ignore", "pipe", "pipe"], + env: { PATH: process.env.PATH, MONGO_URL: process.env.MONGO_URL } + } + ); - child.stdout.on('data', (chunk) => { - console.info(`\x1b[34m${chunk.toString()}\x1b[0m`); - }); + Object.assign(__e2e, { childProcessPid: child.pid }); - child.stderr.on('data', (chunk) => { - const str = chunk.toString(); - if (/DeprecationWarning/.test(str)) { - return; - } - console.error('child::stderr', str); - }); - - process.on('uncaughtException', (err) => { - console.error('UncaughtException!'); - console.error(err); - kill(child.pid, 'SIGKILL', () => process.exit(1)); - }); - - waitForServerToBeReady() - .then(checkAdminCredentials) - .then(createTestUser) - .then(resolve) - .catch((err) => { - kill(child.pid, 'SIGKILL', () => reject(err)); + child.stdout.on('data', (chunk) => { + console.info(`\x1b[34m${chunk.toString()}\x1b[0m`); + }); + + child.stderr.on('data', (chunk) => { + const str = chunk.toString(); + if (/DeprecationWarning/.test(str)) { + return; + } + console.error('child::stderr', str); }); + + process.on('uncaughtException', (err) => { + console.error('UncaughtException!'); + console.error(err); + kill(child.pid, 'SIGKILL', () => process.exit(1)); + }); + + waitForServerToBeReady() + .then(checkAdminCredentials) + .then(createTestUser) + .then(resolve) + .catch((err) => { + console.log('there was an error'); + kill(child.pid, 'SIGKILL', () => reject(err)); + }) + }).catch((error)=> console.log(error)); }); // Export globals - ugly... :-( diff --git a/projects/04-burger-queen-api/GETTING-STARTED.md b/projects/04-burger-queen-api/guides/GETTING-STARTED-DOCKER.md similarity index 61% rename from projects/04-burger-queen-api/GETTING-STARTED.md rename to projects/04-burger-queen-api/guides/GETTING-STARTED-DOCKER.md index dc6b0dda2..69f4440b3 100644 --- a/projects/04-burger-queen-api/GETTING-STARTED.md +++ b/projects/04-burger-queen-api/guides/GETTING-STARTED-DOCKER.md @@ -4,48 +4,17 @@ Una vez creado tu fork y clonado el repo en tu computadora, antes de poder comenzar a codear, tenemos primero que crear nuestro _entorno de desarrollo_. Para ello te recomendamos seguir los pasos a continuación: -* [1. Elegir base de datos](#1-elegir-base-de-datos) -* [2. Instalar `docker` y `docker-compose`](#2-instalar-docker-y-docker-compose) -* [3. Configurar "servicio" de base de datos](#3-configurar-servicio-de-base-de-datos) -* [4. Configurar conexión a BBDD en "servicio" node](#4-configurar-conexión-a-bbdd-en-servicio-node) -* [5. Elegir módulo (cliente)](#5-elegir-módulo-cliente) -* [6. Iniciar, re-iniciar y parar los servicios con `docker-compose`](#6-iniciar-re-iniciar-y-parar-los-servicios-con-docker-compose) -* [7. Familiarizarte con admisitración de contenedores](#7-familiarizarte-con-admisitración-de-contenedores) -* [8. Opcionalmente, instalar interfaz gráfica para admisitrar data](#8-opcionalmente-instalar-interfaz-gráfica-para-admisitrar-data) -* [9. Definir esquemas](#9-definir-esquemas) -* [10. Definir estrategia de pruebas unitarias](#10-definir-estrategia-de-pruebas-unitarias) -* [11. Familiarizarte con las pruebas de integración (e2e)](#11-familiarizarte-con-las-pruebas-de-integración-e2e) +* [1. Instalar `docker` y `docker-compose`](#1-instalar-docker-y-docker-compose) +* [2. Configurar "servicio" de base de datos](#2-configurar-servicio-de-base-de-datos) +* [3. Configurar conexión a BBDD en "servicio" node](#3-configurar-conexión-a-bbdd-en-servicio-node) +* [4. Iniciar, re-iniciar y parar los servicios con `docker-compose`](#4-iniciar-re-iniciar-y-parar-los-servicios-con-docker-compose) +* [5. Familiarizarte con administración de contenedores](#5-familiarizarte-con-admisitración-de-contenedores) +* [6. Opcionalmente, instalar interfaz gráfica para administrar data](#6-opcionalmente-instalar-interfaz-gráfica-para-administrar-data) +* [7. Corre las pruebas de integración (e2e)](#7-corre-las-pruebas-de-integración-e2e) *** -## 1. Elegir base de datos - -La primera decisión que tenemos que tomar, antes de comenzar a programar, es -elegir una base de datos. En este proyecto se sugieren 3 opciones: dos de ellas -_relacionales_ y basadas en SQL, (PostgreSQL y MySQL), y otra _no relacional_ -(MongoDB). Las 3 son excelentes opciones. - -Algunos puntos a tener en cuenta: - -* MongoDB es la más _común_ (popular) a día de hoy en el ecosistema de - Node.js. -* Las bases de datos _relacionales_ normalmente requieren más diseño - _a priori_ (definir tablas, columnas, relaciones, ...) mientras que las - _no relacionales_ nos permiten ser más _flexibles_. -* Las bases de datos _relacionales_ nos permiten relacionar datos de forma - más natural y garantizar la consistencia de la data. Nos dan una rigidez - que quita _flexibilidad_ pero agrega otro tipo de garantías, además de - permitirnos pensar en tablas y columnas, que es una idea con la que muchas - ya están familiarizadas. -* MySQL, PostgreSQL y MongoDB (en ese orden) son las [bases de datos de - código abierto (Open Source) más populares a diciembre de 2020](https://www.statista.com/statistics/809750/worldwide-popularity-ranking-database-management-systems/). - Esto en el panorama general de las bases de datos, no solo el ecosistema de - Node.js. -* PostgreSQL es una base datos _objeto-relacional_ (ORDBMS), mientras que - MySQL es puramente relacional. PostgreSQL tiene soporte nativo para objetos - JSON y otras características como indización de JSON. - -## 2. Instalar `docker` y `docker-compose` +## 1. Instalar `docker` y `docker-compose` Independientemente de qué base datos elijas, en este proyecto vamos a ejecutar localmente (en nuestra computadora) el servidor de bases de datos usando @@ -59,7 +28,7 @@ tu sistema opetativo. * [Get Docker](https://docs.docker.com/get-docker/) * [Install Docker Compose](https://docs.docker.com/compose/install/) -## 3. Configurar "servicio" de base de datos +## 2. Configurar "servicio" de base de datos El boilerplate de este proyecto incluye un archivo [`docker-compose.yml`](./docker-compose.yml) que ya contiene parte de la @@ -128,7 +97,7 @@ db: - private ``` -## 4. Configurar conexión a BBDD en "servicio" node +## 3. Configurar conexión a BBDD en "servicio" node Ahora que ya tenemos la configuración del _servicio_ `db`, tenemos que completar la configuración del _servicio_ de Node.js. En particular nos @@ -167,80 +136,7 @@ contenedores. Siguiendo con los ejemplos del punto anterior, la variable DB_URL: mysql://bq:secret@db:3306/bq ``` -## 5. Elegir módulo (cliente) - -Ahora que ya tenemos un servidor de bases de datos vamos a necesitar elegir un -módulo o librería diseñado para interactuar con nuestra base de datos desde -Node.js. Existen un montón de opciones, pero para este proyecto te recomendamos -elegir una de estas (que son las más populares para cada una de las bases de -datos): [Mongoose](https://mongoosejs.com/) (MongoDB), -[pg](https://www.npmjs.com/package/pg) (PostgreSQL) o -[mysql](https://www.npmjs.com/package/mysql) (MySQL). - -El _boilerplate_ ya incluye un archivo `config.js` donde se leen las -variables de entorno, y entre ellas está `DB_URL`. Como vemos ese valor lo -estamos asignando en la propiedad `dbUrl` del módulo `config`. - -```js -// `config.js` -exports.dbUrl = process.env.DB_URL || "mongodb://localhost:27017/test"; -``` - -Ahora que ya sabemos dónde encontrar el _connection string_ (en el módulo -config), podemos proceder a establecer una conexión con la base de datos -usando el cliente elegido. - -Ejemplo de conexión usando [Mongoose](https://mongoosejs.com/) (MongoDB): - -```js -const mongoose = require("mongoose"); -const config = require("./config"); - -mongoose - .connect(config.dbUrl, { - useNewUrlParser: true, - useUnifiedTopology: true, - }) - .then(console.log) - .catch(console.error); -``` - -Ejemplo de conexión usando [pg](https://www.npmjs.com/package/pg) -(PostgreSQL): - -```js -const pg = require("pg"); -const config = require("./config"); - -const pgClient = new pg.Client({ connectionString: config.dbUrl }); - -pgClient.connect(); -pgClient.query("SELECT NOW()", (err, res) => { - console.log(err, res); - pgClient.end(); -}); -``` - -Ejemplo de conexión usando [mysql](https://www.npmjs.com/package/mysql) -(MySQL): - -```js -const mysql = require("mysql"); -const config = require("./config"); - -const connection = mysql.createConnection(config.dbUrl); - -connection.connect(); -connection.query("SELECT 1 + 1 AS solution", (error, results) => { - if (error) { - return console.error(error); - } - console.log(`The solution is: ${results[0].solution}`); -}); -connection.end(); -``` - -## 6. Iniciar, re-iniciar y parar los servicios con `docker-compose` +## 4. Iniciar, re-iniciar y parar los servicios con `docker-compose` Ahora que ya tenemos nuestra configuración de `docker-compose` lista, veamos cómo podemos _levantar_ la aplicación. Para eso usamos el comando @@ -293,7 +189,7 @@ docker-compose stop db docker-compose restart db ``` -## 7. Familiarizarte con admisitración de contenedores +## 5. Familiarizarte con administración de contenedores Además de los comandos que ya hemos visto de `docker-compose`, te recomendamos familiarizarte con estos otros comandos (entre otros) para poder _administrar_ @@ -349,7 +245,7 @@ podríamos hacer esto: docker-compose help up ``` -## 8. Opcionalmente, instalar interfaz gráfica para administrar data +## 6. Opcionalmente, instalar interfaz gráfica para administrar data A la hora de trabajar con bases de datos es muy común usar algún tipo de interfaz gráfica que nos permita ver y manipular visualmente nuestra data. @@ -417,46 +313,7 @@ NOTA: Para conectar desde pgAdmin usando un contenedor, usa el _nombre_ del contenedor de la base datos (ie: `XXX-001-burger-queen-api_db_1`) como nombre de host para que pgAdmin se pueda conectar a través de la red _privada_. -## 9. Definir esquemas - -Llegado a este punto ya deberíamos tener una configuración de `docker-compose` -capaz de _levantar_ la base datos y servidor de Node.js. - -Como parte del proceso de diseño de nuestra base de datos vamos a tener que -especificar los _esquemas_ de nuestros _modelos_ de datos. Con esto nos -referimos a que tenemos que _describir_ de alguna forma las colecciones o -tablas que vamos a usar y la _forma_ de los objetos o filas que vayamos a -guardar en esas colecciones. - -Si has elegido MongoDB y Mongoose, este último nos ofrece un mecanismo para -describir esos [_modelos_](https://mongoosejs.com/docs/models.html) y -[_esquemas_](https://mongoosejs.com/docs/guide.html) de datos en JavaScript. - -Si has elegido usar una base de datos SQL, es común incluir algunos scripts -`.sql` con el código SQL que nos permita _crear_ (o alterar) las tablas -necesarias. Alternativamente, podrías también explorar abstracciones más -modernas como [Prisma](https://www.prisma.io/). - -## 10. Definir estrategia de pruebas unitarias - -Además de las pruebas `e2e` que ya incluye el _boilerplate_ del proyecto, se -espera que puedas también usar pruebas _unitarias_ para el desarrollo de los -diferentes _endpoints_ o _rutas_ así como otros módulos internos que decidas -desarrollar. - -Para hacer pruebas unitarias de _rutas_ de Express, te recomendamos explorar la -librería [`supertest`](https://www.npmjs.com/package/supertest), que puedes usar -en combinación con `jest`. - -Otro punto a tener en cuenta en las pruebas unitarias, es cómo _mockear_ la base -de datos. Algunas bases de datos ofrecen herramientas (como -[`mongodb-memory-server`](https://github.com/nodkz/mongodb-memory-server)) que -nos permiten usar una base de datos en memoria y así evitar hacer _mocks_ per -se, pero por lo general querremos considerar cómo abstraer la interacción -con la base de datos para facilitar _mocks_ que nos permitan concentrarnos en -la lógica de las rutas. - -## 11. Familiarizarte con las pruebas de integración (e2e) +## 7. Corre las pruebas de integración (e2e) El _boilerplate_ de este proyecto ya incluye pruebas `e2e` (end-to-end) o de _integración_, que se encargan de probar nuestra aplicación en conjunto, diff --git a/projects/04-burger-queen-api/guides/GETTING-STARTED-DOCKER.pt.md b/projects/04-burger-queen-api/guides/GETTING-STARTED-DOCKER.pt.md new file mode 100644 index 000000000..63042a114 --- /dev/null +++ b/projects/04-burger-queen-api/guides/GETTING-STARTED-DOCKER.pt.md @@ -0,0 +1,348 @@ +# Primeiros passos + +Depois de criar o fork e clonar o repositório em seu computador, +antes de começar a codificar, precisamos criar nosso _ambiente de desenvolvimento_. +Recomendamos que você siga as etapas a seguir: + +* [1. Instalar `docker` e `docker-compose`](#1-instalar-docker-y-docker-compose) +* [2. Configurar o "serviço" de banco de dados](#2-configurar-servicio-de-base-de-datos) +* [3. Configurar a conexão com o banco de dados no "serviço" node](#3-configurar-conexión-a-bbdd-en-servicio-node) +* [4. Iniciar, reiniciar e parar os serviços com `docker-compose`](#4-iniciar-re-iniciar-y-parar-los-servicios-con-docker-compose) +* [5. Familiarizar-se com a administração de contêineres](#5-familiarizarte-con-admisitración-de-contenedores) +* [6. Opcionalmente, instalar uma interface gráfica para administrar dados](#6-opcionalmente-instalar-interfaz-gráfica-para-administrar-data) +* [7. Execute os testes de integração (e2e)](#7-corre-las-pruebas-de-integración-e2e) + +*** + +## 1. Instale o docker e o docker-compose + +Independentemente do banco de dados que você escolher, neste projeto iremos executar +localmente (em nosso computador) o servidor de banco de dados usando +contêineres do Docker, em vez de instalar o programa diretamente em nosso +computador. Além disso, também iremos usar a ferramenta `docker-compose` para +orquestrar nossos contêineres: banco de dados e servidor web (node). + +Nos seguintes links, você pode ver como instalar o `docker` e o `docker-compose` +em seu sistema operacional. + +* [Get Docker](https://docs.docker.com/get-docker/) +* [Install Docker Compose](https://docs.docker.com/compose/install/) + +## 2. Configurando o "serviço" de banco de dados + +O boilerplate deste projeto inclui um arquivo +[`docker-compose.yml`](./docker-compose.yml) que já contém parte da +configuração do `docker-compose`. Neste arquivo, você verá que existem dois +serviços listados: `db` e `nod`e. Nossa aplicação consistirá em dois servidores: +um servidor de banco de dados (o serviço `db`) e um servidor web implementado +em Node.js (o serviço `node`). + +Na seção correspondente ao serviço `db`, existem três coisas importantes que +precisaremos completar: + +* Qual _imagem_ (`image`) queremos usar. Imagens recomendadas: + [mongo](https://hub.docker.com/_/mongo), + [postgres](https://hub.docker.com/_/postgres) y + [mysql](https://hub.docker.com/_/mysql). +* Quais volumes (`volumes`), arquivos ou pastas queremos mapear para o + contêiner, como por exemplo, o diretório de dados (a pasta onde o + banco de dados irá armazenar seus arquivos). +* As variáveis de ambiente (`environment`) necessárias para configurar nosso + banco de dados e usuários. Esses dados serão utilizados posteriormente + para configurar a conexão a partir do Node.js. + +Exemplo de serviço `db` usando: [MongoDB](https://hub.docker.com/_/mongo): + +```yml +db: + image: mongo:4 + volumes: + - ./db-data:/data/db + environment: + MONGO_INITDB_ROOT_USERNAME: bq + MONGO_INITDB_ROOT_PASSWORD: secret + restart: always + networks: + - private +``` + +Exemplo de serviço `db` usando [PostgreSQL](https://hub.docker.com/_/postgres): + +```yml +db: + image: postgres:13 + volumes: + - ./db-data:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: secret + restart: always + networks: + - private +``` + +Exemplo de serviço `db` usando [MySQL](https://hub.docker.com/_/mysql): + +```yml +db: + image: mysql:5 + volumes: + - ./db-data:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: supersecret + MYSQL_DATABASE: bq + MYSQL_USER: bq + MYSQL_PASSWORD: secret + restart: always + networks: + - private +``` + +## 3. Configurar conexão ao BD no serviço node + +Agora que temos a configuração do serviço db, precisamos completar a +configuração do serviço Node.js. Em particular, queremos definir o valor +da variável de ambiente `DB_URL`, onde colocaremos a connection string +correspondente ao nosso banco de dados. Esta string de conexão segue +o formato de URL e se parece com isso: + +```text +protocol://username:password@host:port/dbname?opt1=val1&... +``` + +Aqui, substituiremos `protocol` pelo nome do protocolo do banco de dados +escolhido (`mongodb`, `postgresql` ou `mysql`), e `username`, `password` e `dbname` +pelos valores usados na configuração do serviço db no ponto anterior. +Neste caso, o valor de host será `db`, que é o nome do serviço de banco de dados +na configuração do `docker-compose.yml`, e podemos nos referir a ele pelo nome +na rede interna entre os contêineres. +Seguindo os exemplos do ponto anterior, a variável `DB_URL` no `docker-compose.yml` +seria assim: + +* MongoDB: + + ```yml + DB_URL: mongodb://bq:secret@db:27017/bq?authSource=admin + ``` + +* PostgreSQL: + + ```yml + DB_URL: postgresql://postgres:secret@db:5432/postgres?schema=public + ``` + +* MySQL: + + ```yml + DB_URL: mysql://bq:secret@db:3306/bq + ``` + +## 4. Iniciar, reiniciar e parar os serviços com `docker-compose` + +Agora que temos nossa configuração do docker-compose pronta, +vamos ver como podemos iniciar a aplicação. +Para isso, usamos o comando `docker-compose up` dentro da pasta do +nosso projeto (onde está o arquivo `docker-compose.yml`). + +```sh +docker-compose up +``` + +Para interromper o comando e ter o terminal de volta ao _prompt_, +você pode usar a combinação de teclas `Ctrl + C`. + +Se usarmos o comando dessa forma, sem opções, ele iniciará todos os serviços +descritos no `docker-compose.yml`. Alternativamente, podemos iniciar um serviço +específico adicionando o nome do serviço ao comando. +Por exemplo, se quisermos iniciar apenas o serviço de banco de dados: + +```sh +docker-compose up db +``` + +Também temos a opção de iniciar os serviços e executá-los em segundo plano, +como _daemons_, usando a opção `-d`, para que o prompt seja +imediatamente retornado e os serviços continuem em execução. + +```sh +docker-compose up -d +``` + +Além do comando `docker-compose up`, que constrói, (re)cria, inicia e se conecta +aos contêineres de um serviço, também temos comandos disponíveis para +iniciar (`start`), reiniciar (`restart`) e parar (`stop`) serviços com contêineres +já existentes. + +```sh +docker-compose start +docker-compose stop +docker-compose restart +``` + +Assim como com `docker-compose up`, com esses outros comandos também podemos +especificar com qual serviço queremos interagir (ou com todos, se não for especificado). +Por exemplo, para iniciar, reiniciar e depois parar o servidor de banco de dados: + +```sh +docker-compose start db +docker-compose stop db +docker-compose restart db +``` + +## 5. Familiarize-se com a administração de contêineres + +Além dos comandos que já vimos com `docker-compose`, recomendamos +que você se familiarize com outros comandos (entre outros) para poder _administrar_ +seus contêineres. + +O comando `docker-compose ps` exibe uma lista com os contêineres _ativos_: + +```sh +docker-compose ps +``` + +Também podemos listar _todos_ os contêineres, incluindo os que estão parados, +usando a opção `-a`: + +```sh +docker-compose ps -a +``` + +Para remover os contêineres dos serviços: + +```sh +docker-compose rm +``` + +Assim como nos comandos anteriores, também podemos remover os contêineres +de um serviço específico indicando seu nome: + +```sh +docker-compose rm db +``` + +Por fim, quando executamos nossos serviços em segundo plano, como _daemons_, +para nos conectarmos aos contêineres e vermos os _logs_, podemos usar: + +```sh +docker-compose logs +``` + +Podemos adicionar também a opção `-f` para fazer streaming dos logs e ficar ouvindo + assim como especificar um serviço em particular. Por exemplo: + +```sh +docker-compose logs -f db +``` + +Lembre-se de sempre consultar a _ajuda_ do `docker-compose` com o +comando `help`. Por exemplo, se quisermos ver a ajuda do subcomando +up, poderíamos fazer isso: + +```sh +docker-compose help up +``` + +## 6. Opcionalmente, instale uma interface gráfica para administrar dados + +Ao trabalhar com bancos de dados, é muito comum usar algum tipo de interface +gráfica que nos permita visualizar e manipular nossos dados de forma visual. +Existem opções para cada banco de dados. Recomendamos as seguintes: + +[Compass](https://www.mongodb.com/products/compass) (MongoDB), +[Workbench](https://www.mysql.com/products/workbench/) (MySQL), +[pgAdmin](https://www.pgadmin.org/) (PostgreSQL). + +Se você deseja usar esse tipo de ferramenta (como o `Compass` ou o `Workbench`), +provavelmente precisará tornar seu banco de dados visível fora do Docker. +Para fazer isso, você pode mapear a porta do banco de dados no contêiner +para uma porta disponível no host do Docker (normalmente, seu computador). +Normalmente, vamos mapear essas portas padrão (por exemplo, `27017` para o MongoDB) +para números de porta diferentes, pois esses programas e/ou suas portas podem estar +em uso. Por exemplo, se estivermos usando o MongoDB, poderíamos adicionar +o seguinte mapeamento de portas ao serviço db em nosso `docker-compose.yml`: + +```yaml +ports: + - 28017:27017 +``` + +Ao listar as portas de um contêiner ou serviço no `docker-compose.yml`, +tenha em mente que o número à direita é a porta no contêiner +(rede privada do Docker), enquanto o número à esquerda é a porta no +host do Docker (geralmente o seu computador - `127.0.0.1` ou `localhost`). +No exemplo acima, estamos "mapeando" a porta `27017` do contêiner para a +porta `28017` do host do Docker. + +Se você estiver usando PostgreSQL ou MySQL, as portas que gostaríamos de mapear +seriam `5432` e `330`6, respectivamente. + +Se estamos "expondo" a porta em nosso computador (o "host"), +também será necessário conectar o contêiner `db` à rede "pública": + +```yaml +networks: + - public + - private +``` + +Após essa alteração, você poderá acessar usando `127.0.0.1` ou `localhost` +e a porta à qual mapeamos, `28017` neste exemplo. + +Se você escolher o [pgAdmin](https://www.pgadmin.org/) (PostgreSQL), +a opção mais fácil é usar o pgAdmin como um contêiner e adicioná-lo +como um novo serviço ao nosso `docker-compose.yml`. Por exemplo: + +```yml +pgadmin: + image: dpage/pgadmin4 + restart: always + environment: + PGADMIN_DEFAULT_EMAIL: user@domain.com + PGADMIN_DEFAULT_PASSWORD: secret + ports: + - 8088:80 + networks: + - public + - private +``` + +NOTA: Para conectar desde pgAdmin usando um contêiner, use o _nome_ do contêiner +do banco de dados (por exemplo: `XXX-001-burger-queen-api_db_1`) como nome do host +para que o pgAdmin possa se conectar através da rede _privada_. + +## 7. Execute os testes de integração (e2e) + +O _boilerplate_ deste projeto já inclui testes `e2e` (end-to-end) ou de integração, +que são responsáveis por testar nossa aplicação como um todo, através da +interface HTTP. Ao contrário dos testes unitários, onde importamos ou requeremos +um módulo e testamos uma função de forma isolada, aqui iremos iniciar toda a +aplicação e testá-la como se estivéssemos usando no mundo real. Para isso, +os testes de integração precisarão de um banco de dados e estarão ouvindo em +uma porta de rede. + +Para executar os testes e2e em uma instância local, podemos usar: + +```sh +npm run test:e2e +``` + +Isso iniciará a aplicação com `npm start` e executará os testes na +URL desta instância (por padrão `http://127.0.0.1:8080`). +Isso pressupõe que o banco de dados esteja disponível. + +Alternativamente, e talvez mais fácil de usar, podemos iniciar nossa aplicação +usando `docker-compose`, ou até mesmo em produção, e em seguida, executar os +testes e2e passando a URL da aplicação na variável de ambiente `REMOTE_URL`. +Por exemplo: + +```sh +REMOTE_URL=http://127.0.0.1:8080 npm run test:e2e +``` + +Ao especificar `REMOTE_URL`, os testes não tentarão _iniciar_ um servidor local, +mas usarão diretamente a URL fornecida, assumindo que a aplicação esteja disponível +nessa URL. Isso nos permite testar também em URLs remotas. Por exemplo: + +```sh +REMOTE_URL=https://api.my-super-app.com npm run test:e2e +``` diff --git a/projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.md b/projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.md new file mode 100644 index 000000000..abda2413b --- /dev/null +++ b/projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.md @@ -0,0 +1,268 @@ +# Primeros pasos con MongoDB + +MongoDB es un base de datos no-relacional, y es la más _común_ (popular) +a día de hoy en el ecosistema de Node.js. + +Si vas a trabajar con MongoDB y Docker, mejor lee primero +[**la guía de _primeros pasos con Docker_**](./GETTING-STARTED-DOCKER.md). +Si vas a instalar MongoDB y desarrollar el proyecto sin +Docker en este momento, sigue leyendo esta guía. + +Una vez creado tu fork y clonado el repo en tu computadora, haces `npm install` +para instalar las dependencias básicas. +Antes de poder comenzar a codear, tenemos que crear nuestro _entorno de desarrollo_. +Para ello te recomendamos seguir los siguientes pasos: + +* [1. Instalar MongoDB y Compass](#1-instalar-mongodb-y-compass) +* [2. Levanta la base de datos y servidor](#2-levanta-la-base-de-datos-y-servidor) +* [3. Elegir módulo (cliente)](#3-elegir-módulo-cliente) +* [4. Definir esquemas](#4-definir-esquemas) +* [5. Implementar los primeros TODOs](#5-implementar-los-primeros-todos) +* [6. Definir estrategia de pruebas unitarias](#6-definir-estrategia-de-pruebas-unitarias) +* [7. Familiarizarte con las pruebas de integración (e2e)](#7-familiarizarte-con-las-pruebas-de-integración-e2e) + +*** + +## 1. Instalar MongoDB y Compass + +El sitio de MongoDB tiene tutoriales de cómo instalar la [Community Edition](https://www.mongodb.com/docs/compass/current/install/). +Elige tu plataforma (Windows, Mac, Ubuntu etc) y sigue [el tutorial](https://www.mongodb.com/docs/manual/installation/#mongodb-installation-tutorials). + +Con los tutoriales, vas a descargar y instalar MongoDB en tu sistema, +con algunas herramientas y comandos para usar en la línea de comando. + +También recomendamos que instales [Compass](https://www.mongodb.com/products/compass), +que es un GUI (Graphical User Interface) para interactuar con la base de datos. +Puedes interactuar con MongoDB sin Compass y solo en la linea de comando, +pero un GUI puede ayudarte visualizar y entender lo que está en +la base de datos. Sigue [las instrucciones de instalación de Compass](https://www.mongodb.com/docs/compass/current/install/). + +## 2. Levanta la base de datos y servidor + +Podemos decir que este proyecto tiene dos "servicios", uno es la base de datos para +almacenar los productos, usuarios, etc., y el otro es el servidor para exponer +el API. + +Estos servicios tienen que estar corriendo, para que +el API pueda funcionar. + +Correr el servidor es bien simple: con `npm start` va a ejecutar +[`index.js`](../index.js) que tiene la lógica básica de un servidor con express. + +Cómo levantar el servidor, este depende de tu instalación y sistema. +Por ejemplo, en MacOS si instalaste con `homebrew`, puede usar +`brew services start mongodb-community@6.0` para levantarlo. O sin `homebrew`, +`mongod --config /usr/local/etc/mongod.conf --fork`. En Windows, hay que +levantarlo desde Services console. + +Revisa [la guía de instalación de +](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#run-mongodb-community-edition), +[guía de instalación de Windows](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-windows/#run-mongodb-community-edition-as-a-windows-service), +o tu instalación en particular, para ejemplos en cómo levantarlo. + +## 3. Elegir módulo (cliente) + +Ahora que ya tenemos un servidor de base de datos, vamos a necesitar elegir un +módulo o librería diseñado para interactuar con nuestra base de datos desde +Node.js. Existen un montón de opciones, pero para este proyecto te recomendamos +usar el [Node.js driver de MongoDB](https://www.mongodb.com/docs/drivers/node/current/) +que es la forma más directa de interactuar con tu instancia de MongoDB. + +Hay que instalar el Node.js Driver en este proyecto usando `npm`, +revisa [la documentación oficial para más información](https://www.mongodb.com/docs/drivers/node/current/quick-start/download-and-install/#install-the-node.js-driver). + +El _boilerplate_ ya incluye un archivo `config.js` donde se leen las +variables de entorno, y entre ellas está `DB_URL`. Como vemos ese valor lo +estamos asignando en la propiedad `dbUrl` del módulo `config`. + +```js +// `config.js` +exports.dbUrl = process.env.MONGO_URL || process.env.DB_URL || 'mongodb://127.0.0.1:27017/test'; +``` + +Ahora que ya sabemos dónde encontrar el _connection string_ (en el módulo +config), podemos proceder a establecer una conexión con la base de datos +usando el cliente elegido. + +### Ejemplo de conexión usando MongoDB Node Driver + +```js +const { MongoClient } = require('mongodb'); +const config = require("./config"); + +const client = new MongoClient(config.dbUrl); + +async function connect() { + try { + await client.connect(); + const db = client.db(); // Reemplaza por el nombre del db + return db; + } catch (error) { + // + } +} +``` + +Puedes encontrar mas ejemplos en [la documentación de MongoDB](https://www.mongodb.com/docs/drivers/node/current/). + +## 4. Definir esquemas + +Como parte del proceso de diseño de nuestra base de datos vamos a tener que +especificar los _esquemas_ de nuestros _modelos_ de datos. Con esto nos +referimos a que tenemos que _describir_ de alguna forma la estructura de las colecciones +que vamos a usar y la _forma_ de los objetos que vayamos a +guardar en esas colecciones. + +Puedes usar [la documentación de API](https://app.swaggerhub.com/apis-docs/ssinuco/BurgerQueenAPI/2.0.0) +que describe la estructura de `products`, `orders`, etc. para guiar el diseño. + +## 5. Implementar los primeros TODOs + +El boilerplate del proyecto viene con archivos con lógica para arrancar el server +y otros que contienen funciones de rutas y autenticación, pero muchas están vacías. +Hemos marcado las primeras partes esenciales con comentarios `TODO` +(del inglés _por hacer_), que es una convención en el desarrollo de software, +cuando queda algo pendiente de hacer. + +Aquí te guiamos un poco sobre esto TODO's. + +### TODO 1: Conectar a la base de datos + +En el archivo `connect.js` hay que hacer la conexión con la base de datos. + +```js +const { dbUrl } = config; + +async function connect() { + // TODO: Conexión a la Base de Datos +} +``` + +Aquí debes usar el `dbUrl` que importamos del config para establecer la conexión. +Las funciones que van a interactuar con la base de datos tienen que invocar +`connect`. + +### TODO 2: Crear el usuario _admin_ + +El proyecto depende en la existencia de un usuario en la base de datos que +tiene privilegios de administrador, para así poder crear otros usuarios, etc. + +En `routes/users.js` invocamos una función `initAdminUser(app, next)` +al final de archivo, y definimos esta función arriba en este misma archivo. + +`initAdminUser` está incompleto, y hay un TODO para crear el usuario admin, +donde tienes que primero chequear si un admin ya existe, y si no agregar uno +a la base de datos. + +```js +const initAdminUser = (app, next) => { + const { adminEmail, adminPassword } = app.get('config'); + if (!adminEmail || !adminPassword) { + return next(); + } + + const adminUser = { + email: adminEmail, + password: bcrypt.hashSync(adminPassword, 10), + roles: { admin: true }, + }; + + // TODO: crear usuaria admin + next(); +}; + +Puedes confirmar si tu código funciona revisando la base de datos y con un testeo unitario. + +``` + +### TODO 3: Implementar autenticación de usuario + +En `routes/auth.js` está la ruta '/auth' definida, con un + +```js + // TODO: autenticar a la usuarix + ``` + +Aquí es donde debes verificar que el correo y password coinciden con +datos de algún usuario en la base de datos. Si coinciden, hay que generar un +[JWT token](https://jwt.io/introduction) +y mandarlo en la respuesta, para que el usuario puede usarlo en sus peticiones futuras. +Para ejemplos con mas detalle, busca tutoriales de autenticación con JWT y node/express. + +### TODO 4: Implementar el middleware de autenticación + +En `middleware/auth.js` hay varios `TODOs`. Usa esta oportunidad para familiarizarte +con [el concepto de middleware en express](https://expressjs.com/es/guide/using-middleware.html). + +La aplicación va a usar este middleware para chequear que las peticiones +que requieren autenticación sean autorizados, es decir, que tienen un token válido. + +### TODO 5: Implementar la ruta GET `/users` + +Para juntar y verificar todo el trabajo que has hecho, seria bueno implementar +una ruta básica del API, en este caso recomendamos `/users` porque ya debes +tener el user admin en tu base de datos, y además porque esta ruta usa +el middleware de auth. + +Vas a ver que la ruta `/users` usa la función `getUsers` que está definido en +`controller/users.js`. El concepto de controller nos sirve para separar más +la lógica de la definición de rutas con la implementación que va a hablar con +el base de datos. Hay que implementar `getUsers` para obtener la lista de +users de la colección en tu base de datos. + +Revisa [el tutorial de Node y express en Mozilla](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes) +que habla de controllers. + +### TODO 6: Implementar la ruta POST `/users` + +Los tests e2e invocan la ruta POST `/users` para agregar la usuaria para los tests. +Por lo tanto, antes de poder ejecutar los tests e2e, esta ruta debe funcionar +correctamente. + +## 6. Definir estrategia de pruebas unitarias + +Además de las pruebas `e2e` que ya incluye el _boilerplate_ del proyecto, se +espera que puedas también usar pruebas _unitarias_ para el desarrollo de los +diferentes _endpoints_ o _rutas_ así como otros módulos internos que decidas +desarrollar. + +Para hacer pruebas unitarias de _rutas_ de Express, te recomendamos explorar la +librería [`supertest`](https://www.npmjs.com/package/supertest), que puedes usar +en combinación con `jest`. + +Otro punto a tener en cuenta en las pruebas unitarias, es cómo _mockear_ la base +de datos. Algunas bases de datos ofrecen herramientas (como +[`mongodb-memory-server`](https://github.com/nodkz/mongodb-memory-server)) que +nos permiten usar una base de datos en memoria y así evitar hacer _mocks_ per +se, pero por lo general querremos considerar cómo abstraer la interacción +con la base de datos para facilitar _mocks_ que nos permitan concentrarnos en +la lógica de las rutas. + +## 7. Familiarizarte con las pruebas de integración (e2e) + +El _boilerplate_ de este proyecto ya incluye pruebas `e2e` (end-to-end) o de +_integración_, que se encargan de probar nuestra aplicación en conjunto, +a través de la interfaz HTTP. A diferencia de las pruebas unitarias, en vez +de importar o requerir un módulo y probar una función de forma aislada, lo que +vamos a hacer es arrancar toda la aplicación, y probarla tal como se usaría en +el mundo real, para ello la aplicación de prueba necesitará una base de datos y +escuchar en un puerto de red. + +Para correr pruebas e2e sobre instancia local podemos usar: + +```sh +npm run test:e2e +``` + +Esto levanta la aplicación con `npm start` y corre los tests contra la URL de +esta instancia (por defecto `http://127.0.0.1:8080`). + +Los pruebas e2e dependen del código de (`globalSetup.js`)[../e2e/globalSetup.js] +que `jest` ejecuta en primer lugar, antes de los tests. +Este paso de setup levanta un mock db (como hemos hablado de +[`mongodb-memory-server`](https://github.com/nodkz/mongodb-memory-server)) +y jest se conecta a este mock db. + +Para este configuración usamos `mongodb-memory-server` y +un preset [`jest-mongodb`](https://github.com/shelfio/jest-mongodb) +que ya están incluido en el boilerplate. diff --git a/projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.pt.md b/projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.pt.md new file mode 100644 index 000000000..3bb05f3b5 --- /dev/null +++ b/projects/04-burger-queen-api/guides/GETTING-STARTED-MONGODB.pt.md @@ -0,0 +1,261 @@ +# Primeiros passos com o MongoDB + +O MongoDB é um banco de dados não relacional e é o mais comum (popular) +atualmente no ecossistema Node.js. + +Se você estiver trabalhando com o MongoDB e Docker, é melhor ler primeiro +o guia "Primeiros passos com o Docker". Se você estiver instalando o MongoDB +e desenvolvendo o projeto sem o Docker neste momento, continue lendo este guia. + +Depois de criar o seu fork e clonar o repositório em seu computador, +execute o comando npm install para instalar as dependências básicas. +Antes de começar a codificar, precisamos criar nosso ambiente de desenvolvimento. +Recomendamos seguir os seguintes passos: + +1. [Instalar o MongoDB e o Compass](#1-instalar-o-mongodb-e-o-compass) +2. [Iniciar o banco de dados e o servidor](#2-iniciar-o-banco-de-dados-e-o-servidor) +3. [Escolher o módulo cliente](#3-escolher-um-módulo-cliente) +4. [Definir esquemas](#4-definir-esquemas) +5. [Implementar as primeiras tarefas (TODOs)](#5-implementar-os-primeiros-todos) +6. [Definir estratégia de testes unitários](#6-definir-estratégia-de-testes-unitários) +7. [Familiarizar-se com os testes de integração (e2e)](#7-familiarizar-se-com-os-testes-de-integração-e2e) + +## 1. Instalar o MongoDB e o Compass + +O site do MongoDB possui tutoriais sobre como instalar a [Community Edition](https://www.mongodb.com/docs/compass/current/install/). +Escolha sua plataforma (Windows, Mac, Ubuntu, etc.) e siga [o tutorial](https://www.mongodb.com/docs/manual/installation/#mongodb-installation-tutorials). + +Nos tutoriais, você irá baixar e instalar o MongoDB em seu sistema, +juntamente com algumas ferramentas e comandos para usar no terminal. + +Recomendamos também que você instale o [Compass](https://www.mongodb.com/products/compass), +que é uma GUI (Interface Gráfica do Usuário) para interagir com o banco de dados. +Você pode interagir com o MongoDB sem o Compass apenas no terminal, mas uma +GUI pode ajudá-lo a visualizar e entender o que está no banco de dados. +Siga [as instruções de instalação do Compass](https://www.mongodb.com/docs/compass/current/install/)). + +## 2. Iniciar o banco de dados e o servidor + +Podemos dizer que este projeto possui dois "serviços": +um é o banco de dados para armazenar produtos, usuários, etc., +e o outro é o servidor para expor a API. + +Esses serviços precisam estar em execução para que a API funcione. + +Iniciar o servidor é bastante simples: execute `npm start` para executar +o arquivo [`index.js`](../index.js), que contém a lógica básica de +um servidor com Express. + +Como iniciar o servidor depende da sua instalação e sistema. +Por exemplo, no macOS, se você instalou com o homebrew, pode usar o comando +`brew services start mongodb-community@6.0` para iniciá-lo. +Ou, sem o homebrew, utilize `mongod --config /usr/local/etc/mongod.conf --fork`. +No Windows, é necessário iniciar o serviço pelo console de serviços. + +Consulte o +[guia de instalação para macOS](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#run-mongodb-community-edition), +[guia de instalação para Windows](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-windows/#run-mongodb-community-edition-as-a-windows-service) +ou a documentação específica da sua instalação para obter exemplos de como +iniciar o servidor. + +## 3. Escolher um módulo (cliente) + +Agora que já temos um servidor de banco de dados, precisamos escolher +um módulo ou biblioteca projetado para interagir com nosso banco de dados +a partir do Node.js. Existem muitas opções, mas para este projeto, +recomendamos o uso do [Node.js driver do MongoDB](https://www.mongodb.com/docs/drivers/node/current/) +que é a forma mais direta de interagir com sua instância do MongoDB. + +É necessário instalar o Node.js Driver neste projeto usando o `npm`, +[verifique os documentos para mais informações](https://www.mongodb.com/docs/drivers/node/current/quick-start/download-and-install/#install-the-node.js-driver). + +O _boilerplate_ já inclui um arquivo config.js onde as variáveis +de ambiente são lidas, e uma delas é DB_URL. Conforme podemos ver, +esse valor está sendo atribuído à propriedade dbUrl do módulo config. + +```js +// `config.js` +exports.dbUrl = process.env.MONGO_URL || process.env.DB_URL || 'mongodb://127.0.0.1:27017/test'; +``` + +Agora que sabemos onde encontrar a _connection string_ (no módulo config), +podemos prosseguir e estabelecer uma conexão com o banco de dados usando +o cliente escolhido. + +### Exemplo de conexão usando o driver do MongoDB para Node.js + +```js +const { MongoClient } = require('mongodb'); +const config = require("./config"); + +async function connect() { + try { + await client.connect(); + const db = client.db(); // Reemplaza por el nombre del db + return db; + } catch (error) { + // + } +} +``` + +Você pode encontrar mais exemplos +[na documentação do MongoDB](https://www.mongodb.com/docs/drivers/node/current/). + +## 4. Definir esquemas + +Como parte do processo de design do nosso banco de dados, precisamos +especificar os "esquemas" dos nossos "modelos" de dados. Isso significa +que precisamos descrever de alguma forma a estrutura das coleções que +vamos usar e a forma dos objetos que vamos armazenar nessas coleções. + +Você pode usar [a documentación de API](https://app.swaggerhub.com/apis-docs/ssinuco/BurgerQueenAPI/2.0.0) +que descreve a estrutura de `products`, `orders`, etc. para orientar o design. + +## 5. Implementar os primeiros TODOs + +O boilerplate do projeto vem com arquivos contendo a lógica para iniciar o +servidor e outros que contêm funções de rotas e autenticação, mas muitos deles estão +vazios. Marcamos as primeiras partes essenciais com comentários +"TODO" (em inglês, `a fazer`), que é uma convenção no desenvolvimento de software +para indicar algo a ser feito. + +Aqui vamos orientá-lo um pouco sobre esses TODOs. + +### TODO 1: Conectar a la base de datos + +No arquivo `connect.js`, é necessário conectar ao banco de dados.. + +```js +const { dbUrl } = config; + +async function connect() { + // TODO: Conexão com o Banco de Dados +} +``` + +Aqui você deve usar o `dbUrl` que importamos do config para estabelecer a conexão. +As funções que vão interagir com o banco de dados devem invocar o `connect`. + +### TODO 2: Criar o usuário _admin_ + +O projeto depende da existência de um usuário no banco de dados que possui privilégios +de administrador, para que seja possível criar outros usuários, etc. + +No arquivo `routes/users.js` invocamos a função `initAdminUser(app, next)` +no final do arquivo, e definimos essa função acima, no mesmo arquivo. + +A função `initAdminUser` está incompleta e há um TODO para criar o usuário admin, +onde você precisa primeiro verificar se um admin já existe e, caso contrário, +adicioná-lo ao banco de dados. + +```js +const initAdminUser = (app, next) => { + const { adminEmail, adminPassword } = app.get('config'); + if (!adminEmail || !adminPassword) { + return next(); + } + + const adminUser = { + email: adminEmail, + password: bcrypt.hashSync(adminPassword, 10), + roles: { admin: true }, + }; + + // TODO: crear usuaria admin + next(); +}; + +Você pode confirmar se o seu código funciona verificando o banco de +dados e realizando um teste unitário. + +``` + +### TODO 3: Implementar autenticación de usuario + +En routes/auth.js, a rota '/auth' está definida com um + +```js + // TODO: autenticar a la usuarix + ``` + +Aqui é onde você deve verificar se o email e a senha correspondem aos dados de +algum usuário no banco de dados. Se coincidirem, é necessário gerar um +[token JWT](https://jwt.io/introduction) +e enviá-lo na resposta, para que o usuário possa usá-lo em suas futuras +solicitações. Para exemplos mais detalhados, procure tutoriais de autenticação +com JWT e node/express. + +### TODO 4: Implementar o middleware de autenticação + +Em `middleware/auth.js`, existem vários TODOs. +Aproveite esta oportunidade para se familiarizar com o +[conceito de middleware no express](https://expressjs.com/es/guide/using-middleware.html). + +A aplicação usará esse middleware para verificar se as solicitações que exigem +autenticação são autorizadas, ou seja, se possuem um token válido. + +### TODO 5: Implementar a rota GET `/users` + +Para reunir e verificar todo o trabalho que você fez, seria bom implementar +uma rota básica da API, neste caso, recomendamos `/users` porque você já deve +ter o usuário admin em seu banco de dados, e também porque essa rota usa o +middleware de autenticação. + +Você verá que a rota `/users` usa a função `getUsers` que está definida +em `controller/users.js`. +O conceito de controller é usado para separar ainda mais a lógica da +definição de rotas da implementação que irá interagir com o banco de dados. +É necessário implementar a função `getUsers` para obter a lista de +usuários da coleção em seu banco de dados. + +Consulte o [tutorial de Node.js e express na Mozilla](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes) +que aborda os controllers. + +## 6. Definir estratégia de testes unitários + +Além dos testes `e2e` já incluídos no boilerplate do projeto, espera-se +que você também possa usar testes unitários para o desenvolvimento +dos diferentes endpoints ou rotas, bem como outros módulos internos +que decidir desenvolver. + +Para realizar testes unitários em `rotas` do Express, +recomendamos explorar a biblioteca [`supertest`](https://www.npmjs.com/package/supertest), +, que pode ser usada em combinação com o `jest`. + +Outro ponto a ser considerado nos testes unitários é como fazer `mock` do banco +de dados. Alguns bancos de dados oferecem ferramentas (como o +[`mongodb-memory-server`](https://github.com/nodkz/mongodb-memory-server)) que nos +permitem usar um banco de dados em memória e evitar a necessidade de criar `mocks` +propriamente ditos. No entanto, geralmente queremos considerar como +abstrair a interação com o banco de dados para facilitar os `mocks` que nos +permitirão focar na lógica das rotas. + +## 7. Familiarizar-se com os testes de integração (e2e) + +O _boilerplate_ deste projeto já inclui testes `e2e` (end-to-end) ou +de integração, que são responsáveis por testar nossa aplicação como um +todo, por meio da interface HTTP. Ao contrário dos testes unitários, +em vez de importar ou exigir um módulo e testar uma função isoladamente, +iremos iniciar toda a aplicação e testá-la como seria usado no mundo real, +para isso, a aplicação de teste precisará de um banco de dados e escutar em +uma porta de rede. + +Para executar testes `e2e` em uma instância local, podemos usar: + +```sh +npm run test:e2e +``` + +Isso inicia a aplicação com npm start e executa os testes contra a +URL desta instância (por padrão, `http://127.0.0.1:8080`). + +Os testes e2e dependem do código (`globalSetup.js`)[../e2e/globalSetup.js] +que o jest executa primeiro, antes dos testes. Essa etapa de configuração +inicia um banco de dados falso (como mencionamos anteriormente, usando o +[`mongodb-memory-server`](https://github.com/nodkz/mongodb-memory-server)) +e o jest se conecta a esse banco de dados falso. + +Para essa configuração, usamos o mongodb-memory-server e um preset +[`jest-mongodb`](https://github.com/shelfio/jest-mongodb) +que ya están incluido en el boilerplate. diff --git a/projects/04-burger-queen-api/index.js b/projects/04-burger-queen-api/index.js index ae55a7290..01495c960 100644 --- a/projects/04-burger-queen-api/index.js +++ b/projects/04-burger-queen-api/index.js @@ -5,11 +5,9 @@ const errorHandler = require('./middleware/error'); const routes = require('./routes'); const pkg = require('./package.json'); -const { port, dbUrl, secret } = config; +const { port, secret } = config; const app = express(); -// TODO: Conexión a la Base de Datos (MongoDB o MySQL) - app.set('config', config); app.set('pkg', pkg); diff --git a/projects/04-burger-queen-api/jest-mongodb-config.js b/projects/04-burger-queen-api/jest-mongodb-config.js new file mode 100644 index 000000000..283bc5680 --- /dev/null +++ b/projects/04-burger-queen-api/jest-mongodb-config.js @@ -0,0 +1,15 @@ +// Para usar con MongoDB y jest-mongodb +// https://www.npmjs.com/package/@shelf/jest-mongodb + +module.exports = { + mongodbMemoryServerOptions: { + instance: { + dbName: 'jest', + }, + binary: { + version: '4.0.3', + skipMD5: true, + }, + autoStart: false, + }, +}; diff --git a/projects/04-burger-queen-api/package.json b/projects/04-burger-queen-api/package.json index d9445fc17..49e9fc1bc 100644 --- a/projects/04-burger-queen-api/package.json +++ b/projects/04-burger-queen-api/package.json @@ -17,10 +17,12 @@ "docs:deploy": "rm -rf docs && npm run docs:generate && gh-pages -d docs" }, "dependencies": { + "@shelf/jest-mongodb": "^4.1.7", "bcrypt": "^5.0.1", "body-parser": "^1.19.0", "express": "^4.17.1", - "jsonwebtoken": "^8.5.1" + "jsonwebtoken": "^8.5.1", + "mongodb-memory-server": "^8.12.2" }, "devDependencies": { "docdash": "^1.2.0", diff --git a/projects/04-burger-queen-api/routes/auth.js b/projects/04-burger-queen-api/routes/auth.js index ff3d6426e..2ba383895 100644 --- a/projects/04-burger-queen-api/routes/auth.js +++ b/projects/04-burger-queen-api/routes/auth.js @@ -25,6 +25,10 @@ module.exports = (app, nextMain) => { } // TODO: autenticar a la usuarix + // Hay que confirmar si el email y password + // coinciden con un user en la base de datos + // Si coinciden, manda un access token creado con jwt + next(); }); diff --git a/projects/04-burger-queen-api/routes/users.js b/projects/04-burger-queen-api/routes/users.js index 33e489355..2ce774c96 100644 --- a/projects/04-burger-queen-api/routes/users.js +++ b/projects/04-burger-queen-api/routes/users.js @@ -22,6 +22,9 @@ const initAdminUser = (app, next) => { }; // TODO: crear usuaria admin + // Primero ver si ya existe adminUser en base de datos + // si no existe, hay que guardarlo + next(); }; @@ -115,6 +118,8 @@ module.exports = (app, next) => { * @code {403} si ya existe usuaria con ese `email` */ app.post('/users', requireAdmin, (req, resp, next) => { + // TODO: implementar la ruta para agregar + // nuevos usuarios }); /**