🐳 Rodando no Docker vs Localmente
⚠ Antes de começar, seu docker-compose precisa estar na versão 1.29 ou superior. Veja aqui ou na documentação como instalá-lo. No primeiro artigo, você pode substituir onde está com 1.26.0
por 1.29.2
.
ℹ️ Renomeie o arquivo
src/server.example.ts
, retirando o.example
, e descomente o conteúdo do mesmo. Rode os serviçosapp-car-shop
emongodb
com o comandodocker-compose up -d
.
- Lembre-se de parar o
mongo
se estiver usando localmente na porta padrão (27017
), ou adapte, caso queria fazer uso da aplicação em containers - Esses serviços irão inicializar um container chamado
car_shop
e outro chamadocar_shop_db
. - A partir daqui você pode rodar o container
car_shop
via CLI ou abri-lo no VS Code.
ℹ️ Use o comando
docker exec -it car_shop bash
.
-
Ele te dará acesso ao terminal interativo do container criado pelo compose, que está rodando em segundo plano.
-
⚠ Atenção: Caso opte por utilizar o Docker, TODOS os comandos disponíveis no
package.json
(npm start, npm test, npm run dev, ...) devem ser executados DENTRO do container, ou seja, no terminal que aparece após a execução do comandodocker exec
citado acima. -
⚠ Atenção: O git dentro do container não vem configurado com suas credenciais. Ou faça os commits fora do container, ou configure as suas credenciais do git dentro do container.
-
⚠ Atenção: Não rode o comando npm audit fix! Ele atualiza várias dependências do projeto, e essa atualização gera conflitos com o avaliador.
-
✨ Dica: A extensão
Remote - Containers
(que estará na seção de extensões recomendadas do VS Code) é indicada para que você possa desenvolver sua aplicação no container Docker direto no VS Code, como você faz com seus arquivos locais.
ℹ️ Instale as dependências [Caso existam] com
npm install
⚠ Atenção: Não rode o comando npm audit fix! Ele atualiza várias dependências do projeto, e essa atualização gera conflitos com o avaliador.
-
✨ Dica: Para rodar o projeto desta forma, obrigatoriamente você deve ter o
node
instalado em seu computador. -
✨ Dica: O avaliador espera que a versão do
node
utilizada seja a 16.
‼ Antes de começar a desenvolver
- Clone o repositório
- Use o comando:
git clone [email protected]:joaolelles/car-shop.git
. - Entre na pasta do repositório que você acabou de clonar:
cd sd-025-b-project-car-shop
- Instale as dependências
npm install
- Crie uma branch a partir da branch
main
- Verifique se você está na branch
main
- Exemplo:
git branch
- Exemplo:
- Se não estiver, mude para a branch
main
- Exemplo:
git checkout main
- Exemplo:
- Agora crie uma branch onde você vai submeter os
commits
do seu projeto- Você deve criar uma branch no seguinte formato:
nome-de-usuario-nome-do-projeto
- Exemplo:
git checkout -b joaozinho-sd-0X-project-car-shop
- Você deve criar uma branch no seguinte formato:
- Adicione as mudanças ao stage do Git e faça um
commit
-
Verifique que as mudanças ainda não estão no stage
- Exemplo:
git status
(deve aparecer listada a pasta joaozinho em vermelho)
- Exemplo:
-
Adicione o novo arquivo ao stage do Git
- Exemplo:
git add .
(adicionando todas as mudanças - que estavam em vermelho - ao stage do Git)git status
(deve aparecer listado o arquivo joaozinho/README.md em verde)
- Exemplo:
-
Faça o
commit
inicial- Exemplo:
git commit -m 'iniciando o projeto x'
(fazendo o primeiro commit)git status
(deve aparecer uma mensagem tipo nothing to commit )
- Exemplo:
- Adicione a sua branch com o novo
commit
ao repositório remoto
- Usando o exemplo anterior:
git push -u origin joaozinho-sd-0X-project-car-shop
- Crie um novo
Pull Request
(PR)
⌨️ Durante o desenvolvimento
-
Faça
commits
das alterações que você fizer no código regularmente. -
Lembre-se de sempre após um (ou alguns)
commits
atualizar o repositório remoto. -
Os comandos que você utilizará com mais frequência são:
git status
(para verificar o que está em vermelho - fora do stage - e o que está em verde - no stage)git add
(para adicionar arquivos ao stage do Git)git commit
(para criar um commit com os arquivos que estão no stage do Git)git push -u nome-da-branch
(para enviar o commit para o repositório remoto na primeira vez que fizer opush
de uma nova branch)git push
(para enviar o commit para o repositório remoto após o passo anterior)
🎛 Linter
Para fazer a análise estática do seu código neste projeto, vamos utilizar o linter ESLint. Assim o código estará alinhado com as boas práticas de desenvolvimento, sendo mais legível e de fácil manutenção!
- Este projeto já vem com as dependências relacionadas ao linter configuradas no arquivo
package.json
- Para poder rodar o
ESLint
basta executar o comandonpm install
dentro do projeto e depoisnpm run lint
. - Se a análise do
ESLint
encontrar problemas no seu código, eles serão mostrados no seu terminal. - Se não houver problema no seu código, nada será impresso no seu terminal.
- Você pode também instalar o plugin do
ESLint
noVSCode
. Para isso, bastar ir em extensions e baixar o pluginESLint
.
⚠️ Informações importantes sobre o projeto
Em cada requisito você encontrará informações demonstrando como sua API deverá se comportar, dada a requisição específica. O não cumprimento de um requisito, total ou parcialmente, impactará em sua avaliação.
O projeto possui uma pasta src
, e é fortemente recomendável que você construa sua aplicação dentro dessa pasta.
Controllers
, Models
, Services
, Interfaces
, Domains
)
.
├── src/
│ ├── Controllers/
│ ├── Domains/
│ ├── Interfaces/
│ ├── middlewares/
│ ├── Models/
│ ├── Routes/
│ ├── Services/
│ └── ...
├── tests/
│ ├── unit/
| │ ├── Services/
| │ ├── ...
| └── ...
└── ...
Dentro da pasta src
foram deixados alguns arquivos de exemplo sendo eles:
src/serve.example.ts
src/app.ts
Lembre-se de renomear o arquivo de server
, removendo o .example
e use o arquivo de app.ts
para concentrar os middlewares de sua aplicação.
Dentro da pasta raiz também existe um arquivo .env.example
, este é o único arquivo que pode ser alterado neste nível. Não altere ou instale novas dependências no arquivo packages.json
, pois o mesmo está travado para essa avaliação.
A conexão do banco local contida no arquivo src/Models/Connection.ts
deverá conter a seguinte variável, ou no .env
:
const MONGO_DB_URL = "mongodb://localhost:27017/CarShop";
Para o avaliador funcionar, mantenha a Connection
como esta! Com a variável process.env.MONGO_URI
em src/Models/Connection.ts
:
const connectToDatabase = (
mongoDatabaseURI = process.env.MONGO_URI || // Não altere
MONGO_DB_URL
) => mongoose.connect(mongoDatabaseURI);
- Lembre-se de não entregar o projeto com nenhum teste ignorado. Testes ignorados serão tratados como testes falhando!
- Não apague, em hipótese alguma, qualquer teste ou arquivo deste repositório.
src/Models
,src/Services
,src/Controllers
,src/Interfaces
,src/Domains
e seus respectivos arquivos criados durante a execução do projeto, devem seguir à risca os nomes informados no README e conforme foi ensinado na seção.- Os testes do projeto DEVEM ser de unidade, testando camadas.
- Quando não especificado o retorno de um código de
status
, utilize os aprendidos até o momento de forma correta.
warnings
, deixamos a conexão com o banco de dados com alguns console.log()
e isso é para auxiliar no desenvolvimento. Se o Mongoose
não subir uma instância do banco de dados com o servidor, o banco de dados não funciona! E por isso deixamos os consoles... Se quiser remover, fique a vontade 😉
👀 Dicas
- O arquivo
src/Models/Connection.ts
possui o código necessário para realizar a conexão com o banco de dados:
import mongoose from "mongoose";
import "dotenv/config";
const MONGO_DB_URL = "mongodb://localhost:27017/CarShop";
const connectToDatabase = (
mongoDatabaseURI = process.env.MONGO_URI || MONGO_DB_URL
) => mongoose.connect(mongoDatabaseURI);
export default connectToDatabase;
- O arquivo
src/app.ts
contém o código necessário para começar a gerenciar osmiddlewares
:
import express from "express";
const app = express();
export default app;
src/app.ts
exporte uma instância do app express
para que os testes funcionem.
-
O endpoint deve ser acessível através do caminho (
/cars
); -
Os carros cadastrados devem ser salvos na collection
cars
do banco de dados; -
Os nomes dos arquivos/classes/interfaces devem ser definidos em inglês e seguir a organização/padronização de diretórios e nomenclatura ensinadas na seção;
-
Os nomes das classes devem possuir os mesmos nomes dos arquivos; (ex:
Pet.ts
--->export default class Pet { }
); -
Os atributos necessários para criar um carro estão na tabela:
Atributos | Descrição |
---|---|
id |
String contendo id do veículo |
model |
String contendo modelo do veículo |
year |
Number contendo ano de fabricação do veículo |
color |
String contendo cor principal do veículo |
status |
Booleano contendo status que define se um veículo pode ou não ser comprado (este atributo deve ser opcional e se não passado, deve ser false ) |
buyValue |
Number contendo valor de compra do veículo |
doorsQty |
Number contendo quantidade de portas de um carro |
seatsQty |
Number contendo quantidade de assentos de um carro |
- O corpo da requisição poderá seguir o formato abaixo:
{
"model": "Marea",
"year": 2002,
"color": "Black",
"status": true,
"buyValue": 15.99,
"doorsQty": 4,
"seatsQty": 5
}
Os seguintes pontos serão avaliados
-
Será validado que existe uma interface de nome
ICar
que representa o contrato usado para cadastrar um carro; -
Será validado que a interface contém os atributos especificados na tabela;
-
Será validado que existe uma classe de domínio com o nome
Car
que representa o objeto carro; -
Será validado que a classe de domínio carro contém os atributos:
doorsQty
eseatsQty
acessíveis apenas a própria classe; -
Será validado que a classe de domínio carro contém os atributos restantes acessíveis a própria classe e suas subclasses;
-
Será validado que a instância da classe de domínio carro recebe como parâmetro um objeto do tipo
ICar
; -
Será validado que é possível cadastrar um carro com sucesso;
- Deve-se retornar um JSON com as seguintes chaves:
{ "id": "6348513f34c397abcad040b2", "model": "Marea", "year": 2002, "color": "Black", "status": true, "buyValue": 15.99, "doorsQty": 4, "seatsQty": 5 }
- A instância de um objeto de domínio deve receber um objeto como parâmetro;
- As exportações devem ser feitas no formato
export default
;
-
O endpoint deve ser acessível através do caminho (
/cars
) e (/cars/:id
); -
Os carros listados devem vir da collection
cars
do banco de dados; -
Através do caminho
/cars/:id
, apenas o carro com oid
presente na URL deve ser retornado;
Os seguintes pontos serão avaliados
- Será validado que é possível listar todos os carros;
- Deve-se retornar um JSON com as seguintes chaves:
[ { "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 2002, "color": "Black", "status": true, "buyValue": 15.99, "doorsQty": 4, "seatsQty": 5 }, { "id": "634852326b35b59438fbea31", "model": "Tempra", "year": 1995, "color": "Black", "buyValue": 39, "doorsQty": 2, "seatsQty": 5 } ]
- Deve-se retornar um JSON com as seguintes chaves:
- Será validado que não é possível listar um carro que não existe;
- Deve-se retornar o
status 404
e um JSON com a seguinte mensagem:{ "message": "Car not found" }
- Deve-se retornar o
- Será validado que não é possível listar um carro quando o formato do
id
esta inválido;- Deve-se retornar o
status 422
e um JSON com a seguinte mensagem:{ "message": "Invalid mongo id" }
- Deve-se retornar o
- Será validado que é possível listar um carro específico com sucesso; - Deve-se retornar um JSON com as seguintes chaves:
json { "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 2002, "color": "Black", "status": true, "buyValue": 15.99, "doorsQty": 4, "seatsQty": 5 }
-
Obrigatoriamente seus arquivos de teste devem ficar no diretório
tests/unit
; -
Obrigatoriamente seus testes devem fazer stub do banco de dados;
-
Opcionalmente você pode parar o serviço do
MongoDB
em sua máquina e executar seus teste com o comandonpm run test:mocha
; -
Só será contabilizada a cobertura, se seus testes não conterem erros.
Os seguintes pontos serão avaliados
-
Será validado que os testes escritos por você estão sendo executados sem erros;
-
Será validado que existe um mínimo de 3 funções na camada
Services
. -
Será validado que a cobertura total das linhas dos arquivos da camada
Services
é maior ou igual a 30%;
-
O endpoint deve ser acessível através do caminho (
/cars/:id
); -
Apenas o carro com o
id
presente na URL deve ser atualizado; -
O corpo da requisição poderá seguir o formato abaixo:
{
"model": "Marea",
"year": 1992,
"color": "Red",
"status": true,
"buyValue": 12.0,
"doorsQty": 2,
"seatsQty": 5
}
Os seguintes pontos serão avaliados
-
Será validado que não é possível alterar um carro que não existe;
- Deve-se retornar o
status 404
e um JSON com a seguinte mensagem:{ "message": "Car not found" }
- Deve-se retornar o
-
Será validado que não é possível alterar um carro quando o formato do
id
esta inválido;- Deve-se retornar o
status 422
e um JSON com a seguinte mensagem:{ "message": "Invalid mongo id" }
- Deve-se retornar o
-
Será validado que é possível alterar um carro com sucesso;
- Deve-se retornar um JSON com as seguintes chaves:
{ "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 1992, "color": "Red", "status": true, "buyValue": 12.0, "doorsQty": 2, "seatsQty": 5 }
-
O endpoint deve ser acessível através do caminho (
/motorcycles
); -
As motos cadastradas devem ser salvas na collection
motorcycles
do banco de dados; -
Os nomes dos arquivos/classes/interfaces devem ser definidos em inglês e seguir a organização/padronização de diretórios e nomenclatura ensinadas na seção;
-
Os nomes das classes devem possuir os mesmos nomes dos arquivos; (ex:
Pet.ts
--->export default class Pet { }
); -
Interface e classe de domínio referentes a carro, obrigatoriamente devem ser refatorados;
-
Os atributos necessários para criar uma moto estão na tabela:
Atributos | Descrição |
---|---|
id |
String contendo id do veículo |
model |
String contendo modelo do veículo |
year |
Number contendo ano de fabricação do veículo |
color |
String contendo cor principal do veículo |
status |
Booleano contendo status que define se um veículo pode ou não ser comprado (este atributo deve ser opcional e se não passado, deve ser false ) |
buyValue |
Number contendo valor de compra do veículo |
category |
String contendo categoria da moto (opções: Street , Custom ou Trail ) |
engineCapacity |
Number contendo capacidade do motor |
- O corpo da requisição poderá seguir o formato abaixo:
{
"model": "Honda Cb 600f Hornet",
"year": 2005,
"color": "Yellow",
"status": true,
"buyValue": 30.0,
"category": "Street",
"engineCapacity": 600
}
Os seguintes pontos serão avaliados
-
Será validado que existe uma interface de nome
IMotorcycle
que representa o contrato usado para cadastrar uma moto; -
Será validado que a interface contém os atributos especificados na tabela;
-
Será validado que existe uma interface de nome
IVehicle
e esta contém os atributos repetidos de carro e moto;- Deve-se refatorar as
Interfaces
se necessário;
- Deve-se refatorar as
-
Será validado que existe uma classe de domínio com o nome
Motorcycle
que representa o objeto moto; -
Será validado que a classe de domínio moto contém os atributos:
category
eengineCapacity
acessíveis apenas a própria classe; -
Será validado que a classe de domínio moto contém os atributos restantes acessíveis a própria classe e suas subclasses;
-
Será validado que a instância da classe de domínio moto recebe como parâmetro um objeto do tipo
IMotorcycle
; -
Será validado que existe uma classe de domínio com o nome
Vehicle
e esta contém os atributos repetidos de carro e moto;- Deve-se refatorar as
Domains
se necessário;
- Deve-se refatorar as
-
Será validado que a classe de domínio veiculo contém os atributos acessíveis a própria classe e suas subclasses;
-
Será validado que existe uma classe de nome
AbstractODM
que representa o modelo de comunicação com o banco e ela serve como abstração para as demais;- Deve-se refatorar as
Models
se necessário;
- Deve-se refatorar as
-
Será validado que é possível cadastrar uma moto com sucesso;
- Deve-se retornar um JSON com as seguintes chaves:
{ "id": "6348513f34c397abcad040b2", "model": "Honda Cb 600f Hornet", "year": 2005, "color": "Yellow", "status": true, "buyValue": 30.0, "category": "Street", "engineCapacity": 600 }
- A instância de um objeto de domínio deve receber um objeto como parâmetro;
- As exportações devem ser feitas no formato
export default
; - Arquivos/códigos feitos para cars
devempodem sofrer refatorações;
-
Obrigatoriamente seus arquivos de teste devem ficar no diretório
tests/unit
; -
Obrigatoriamente seus testes devem fazer stub do banco de dados;
-
Opcionalmente você pode parar o serviço do
MongoDB
em sua máquina e executar seus teste com o comandonpm run test:mocha
; -
Só será contabilizada a cobertura, se seus testes não conterem erros.
Os seguintes pontos serão avaliados
-
Será validado que os testes escritos por você estão sendo executados sem erros;
-
Será validado que existe um mínimo de 5 funções na camada
Services
. -
Será validado que a cobertura total das linhas dos arquivos da camada
Services
é maior ou igual a 60%;
-
O endpoint deve ser acessível através do caminho (
/motorcycles
) e (/motorcycles/:id
); -
As motos listadas devem vir da collection
motorcycles
do banco de dados; -
Através do caminho
/motorcycles/:id
, apenas a moto com oid
presente na URL deve ser retornada;
Os seguintes pontos serão avaliados
- Será validado que é possível listar todas as motos;
- Deve-se retornar um JSON com as seguintes chaves:
[ { "id": "634852326b35b59438fbea2f", "model": "Honda Cb 600f Hornet", "year": 2005, "color": "Yellow", "status": true, "buyValue": 30.0, "category": "Street", "engineCapacity": 600 }, { "id": "634852326b35b59438fbea31", "model": "Honda Cbr 1000rr", "year": 2011, "color": "Orange", "status": true, "buyValue": 59.9, "category": "Street", "engineCapacity": 1000 } ]
- Deve-se retornar um JSON com as seguintes chaves:
- Será validado que não é possível listar uma moto que não existe;
- Deve-se retornar o
status 404
e um JSON com a seguinte mensagem:{ "message": "Motorcycle not found" }
- Deve-se retornar o
- Será validado que não é possível listar uma moto quando o formato do
id
esta inválido;- Deve-se retornar o
status 422
e um JSON com a seguinte mensagem:{ "message": "Invalid mongo id" }
- Deve-se retornar o
- Será validado que é possível listar uma moto específica com sucesso; - Deve-se retornar um JSON com as seguintes chaves:
json { "id": "634852326b35b59438fbea31", "model": "Honda Cbr 1000rr", "year": 2011, "color": "Orange", "status": true, "buyValue": 59.900, "category": "Street", "engineCapacity": 1000 }
-
O endpoint deve ser acessível através do caminho (
/motorcycles/:id
); -
Apenas a moto com o
id
presente na URL deve ser atualizada; -
O corpo da requisição poderá seguir o formato abaixo:
{
"model": "Honda Cb 600f Hornet",
"year": 2014,
"color": "Red",
"status": true,
"buyValue": 45.0,
"category": "Street",
"engineCapacity": 600
}
Os seguintes pontos serão avaliados
-
Será validado que não é possível alterar uma moto que não existe;
- Deve-se retornar o
status 404
e um JSON com a seguinte mensagem:{ "message": "Motorcycle not found" }
- Deve-se retornar o
-
Será validado que não é possível alterar uma moto quando o formato do
id
esta inválido;- Deve-se retornar o
status 422
e um JSON com a seguinte mensagem:{ "message": "Invalid mongo id" }
- Deve-se retornar o
-
Será validado que é possível alterar uma moto com sucesso;
- Deve-se retornar um JSON com as seguintes chaves:
{ "id": "634852326b35b59438fbea2f", "model": "Honda Cb 600f Hornet", "year": 2014, "color": "Red", "status": true, "buyValue": 45.0, "category": "Street", "engineCapacity": 600 }
-
Obrigatoriamente seus arquivos de teste devem ficar no diretório
tests/unit
; -
Obrigatoriamente seus testes devem fazer stub do banco de dados;
-
Opcionalmente você pode parar o serviço do
MongoDB
em sua máquina e executar seus teste com o comandonpm run test:mocha
; -
Só será contabilizada a cobertura, se seus testes não conterem erros.
Os seguintes pontos serão avaliados
-
Será validado que os testes escritos por você estão sendo executados sem erros;
-
Será validado que existe um mínimo de 8 funções na camada
Services
. -
Será validado que a cobertura total das linhas dos arquivos da camada
Services
é maior ou igual a 80%;
-
O endpoint pode ser acessível através do caminho (
/cars/:id
); -
Através do caminho
/cars/:id
, apenas o carro com oid
presente na URL deve ser excluído;
-
Não é possível excluir um carro que não existe;
- Retorne
status 404
e um JSON com a mensagem:{ "message": "Car not found" }
- Retorne
-
Não é possível excluir um carro quando o formato do
id
esta inválido;- Retorne
status 422
e um JSON com a mensagem:{ "message": "Invalid mongo id" }
- Retorne
-
Ao excluir com sucesso, retorne
status 204
sem body;
-
O endpoint pode ser acessível através do caminho (
/motorcycles/:id
); -
Através do caminho
/motorcycles/:id
, apenas a moto com oid
presente na URL deve ser excluída;
- Não é possível excluir uma moto que não existe;
- Retorne
status 404
e um JSON com a mensagem:{ "message": "Motorcycle not found" }
- Retorne
- Não é possível excluir uma moto quando o formato do
id
esta inválido;- Retorne
status 422
e um JSON com a mensagem:{ "message": "Invalid mongo id" }
- Retorne
- Ao excluir com sucesso, retorne
status 204
sem body;
-
Escreva testes para as camadas de
Models
,Services
eControllers
de forma a cobrir 100% das camadas de sua aplicação; -
Se quiser se desafiar, escreva testes de integração também;
-
✨ Dica: Utilize o comando
npm run test:coverage
para verificar a cobertura de seus testes; -
✨ Dica: Não se esqueça que seus arquivos de testes devem ficar no diretório
tests/unit
, outests/integration
; -
✨ Dica: Não se esqueça que seus testes devem fazer stub do banco de dados, quando escritos a nível de unidade.