API para gerenciar uma concessionária de veículos. O objetivo era aplicar os princípios da Programação Orientada a Objetos (POO) na arquitetura Model-Service-Controller (MSC), utilizando TypeScript como linguagem de programação e o ODM (Object Document Mapper) Mongoose para se conectar a um banco de dados MongoDB.
A importância desse projeto residia na criação de uma API seguindo os pilares da POO e a arquitetura MSC, proporcionando benefícios como escalabilidade e facilidade de manutenção da aplicação. Durante o desenvolvimento, foi considerada a capacidade de expansão da API, permitindo futuras mudanças, como a substituição do banco de dados utilizado, sem afetar a estrutura geral da aplicação.
No contexto desse projeto, foram exercitados os pilares da POO, como Herança, Abstração, Encapsulamento e Polimorfismo, bem como foram utilizados Composição e criadas e utilizadas Interfaces. A implementação em TypeScript envolveu a criação de Classes, Instâncias, Atributos, Métodos e Objetos. Além disso, foram aplicados os conhecimentos de MongoDB, TypeScript e POO para desenvolver uma API com as operações de CRUD (Create, Read, Update, Delete).
O escopo do projeto incluiu etapas como a criação de uma rota para cadastrar carros, um endpoint para listar carros, a escrita de testes para cobrir uma porcentagem da camada de Service, uma rota para atualizar carros por ID, uma rota para cadastrar motos, testes adicionais para cobrir uma porcentagem maior da camada de Service e uma rota para listar motos. Como bônus, foi implementada uma rota para atualizar motos por ID, além de mais testes para cobrir uma porcentagem maior da camada de Service.
O projeto foi desenvolvido, com foco na aplicação dos princípios da POO na construção da API. O objetivo final era criar um sistema de gerenciamento de uma concessionária de veículos, utilizando o banco de dados MongoDB e Mongoose.
- Cadastro de carros: O projeto permite cadastrar carros na concessionária, fornecendo informações como marca, modelo, ano, cor e preço.
- Listagem de carros: É possível obter uma lista de todos os carros cadastrados na concessionária.
- Atualização de carros por ID: O projeto oferece uma rota para atualizar as informações de um carro específico com base no seu ID.
- Cadastro de motos: Além dos carros, o projeto permite cadastrar motos na concessionária, fornecendo informações como marca, modelo, ano, cor e preço.
- Listagem de motos: É possível obter uma lista de todas as motos cadastradas na concessionária.
- Atualização de motos por ID: O projeto possui uma rota que permite atualizar as informações de uma moto específica com base no seu ID.
- Programação Orientada a Objetos e princípios SOLID:
- Implementar, em TypeScript:
Classes
,Instâncias
,Atributos
eMétodos
. - Arquitetura Model-Service-Controller (MSC)
-
TypeScript
-
Node.js
-
Express.js
-
MongoDB
-
Mongoose
-
Programação Orientada a Objetos (POO)
-
Arquitetura Model-Service-Controller (MSC)
- Mocha
- Chai
- Sinon
Visão geral
Endpoint | Método HTTP | Descrição |
---|---|---|
/cars |
POST | Cadastra um novo carro |
/cars |
GET | Retorna todos os carros |
/cars/:id |
GET | Retorna o carro especificado no id |
/cars/:id |
PUT | Atualiza um carro especificado no id |
/motorcycles |
POST | Cadastra uma nova moto |
/motorcycles |
GET | Retorna todas as motos |
/motorcycles/:id |
GET | Retorna a moto especificado no id |
/motorcycles/:id |
PUT | Atualiza uma moto especificada no id |
Clique nas setas para ver mais
-
Método POST
Respostas- O corpo da requisição e resposta deve seguir o formato abaixo com excessão do id que é gerado apenas na resposta:
- Status: 201 Created
{ "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 1992, "color": "Red", "status": true, "buyValue": 12.000, "doorsQty": 2, "seatsQty": 5 }
-
Método GET
Respostas
- Status: 200 OK
[ { "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 } ]
- Status: 200 OK
-
Método GET
Respostas
-
Status: 200 OK
{ "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 2002, "color": "Black", "status": true, "buyValue": 15.99, "doorsQty": 4, "seatsQty": 5 }
-
Status 404 Not Found Error
{ "message": "Car not found" }
-
Status 422 Unprocessable
{ "message": "Invalid mongo id" }
-
-
Método PUT
Respostas
-
Status: 200 OK
{ "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 2002, "color": "Black", "status": true, "buyValue": 15.99, "doorsQty": 4, "seatsQty": 5 }
-
Status 404 Not Found Error
{ "message": "Car not found" }
-
Status 422 Unprocessable
{ "message": "Invalid mongo id" }
-
-
Método POST
Respostas- O corpo da requisição e resposta deve seguir o formato abaixo com excessão do id que é gerado apenas na resposta:
- Status: 201 Created
{ "model": "Honda Cb 600f Hornet", "year": 2005, "color": "Yellow", "status": true, "buyValue": 30.000, "category": "Street", "engineCapacity": 600 }
-
Método GET
Respostas
- Status: 200 OK
[ { "id": "634852326b35b59438fbea2f", "model": "Honda Cb 600f Hornet", "year": 2005, "color": "Yellow", "status": true, "buyValue": 30.000, "category": "Street", "engineCapacity": 600 }, { "id": "634852326b35b59438fbea31", "model": "Honda Cbr 1000rr", "year": 2011, "color": "Orange", "status": true, "buyValue": 59.900, "category": "Street", "engineCapacity": 1000 } ]
- Status: 200 OK
-
Método GET
Respostas
-
Status: 200 OK
{ "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 2002, "color": "Black", "status": true, "buyValue": 15.99, "doorsQty": 4, "seatsQty": 5 }
-
Status 404 Not Found Error
{ "message": "Motorcycle not found" }
-
Status 422 Unprocessable
{ "message": "Invalid mongo id" }
-
-
Método PUT
Respostas
-
Status: 200 OK
{ "id": "634852326b35b59438fbea2f", "model": "Honda Cb 600f Hornet", "year": 2014, "color": "Red", "status": true, "buyValue": 45.000, "category": "Street", "engineCapacity": 600 }
-
Status 404 Not Found Error
{ "message": "Motorcycle not found" }
-
Status 422 Unprocessable
{ "message": "Invalid mongo id" }
-
Caso deseje contribuir ou simplesmente rodar o projeto na sua máquina, siga as orientações:
. Clone o repositório
git clone https://github.com/brenolg/Car-Shop-API-Mongoose
. Instale as dependências no diretório raiz
npm install
- Na raíz do projeto rode o comando:
docker-compose up -d
- Em seguida abra o terminal interativo do container:
docker exec -it car_shop bash
- Instale as dependências dentro do container:
npm install
Para rodar os testes de integração desenvolvidos por mim, entre na pasta backend e rode o comando:
npm test
Clique na seta para ver a lista de requisitos.
Rotas Cars
01 - Endpoint /cars onde seja possível cadastrar um carro
Detalhes
- 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.990,
"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.990, "doorsQty": 4, "seatsQty": 5 }
02 - Endpoints para listar carros
Detalhes
- 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 foram 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:
{ "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 2002, "color": "Black", "status": true, "buyValue": 15.99, "doorsQty": 4, "seatsQty": 5 }
- Deve-se retornar um JSON com as seguintes chaves:
03 - Endpoint /cars/:id onde seja possível atualizar um carro por ID
Detalhes
- 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 foram 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:
{ "id": "634852326b35b59438fbea2f", "model": "Marea", "year": 2002, "color": "Black", "status": true, "buyValue": 15.99, "doorsQty": 4, "seatsQty": 5 }
- Deve-se retornar um JSON com as seguintes chaves:
Rotas Motorcycles
01 - Rota /motorcycles onde seja possível cadastrar uma moto
Detalhes
- 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.000,
"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.000, "category": "Street", "engineCapacity": 600 }
02 - Rotas /motorcycles onde seja possível listar motos
Detalhes
- 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.000, "category": "Street", "engineCapacity": 600 }, { "id": "634852326b35b59438fbea31", "model": "Honda Cbr 1000rr", "year": 2011, "color": "Orange", "status": true, "buyValue": 59.900, "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:
{ "id": "634852326b35b59438fbea31", "model": "Honda Cbr 1000rr", "year": 2011, "color": "Orange", "status": true, "buyValue": 59.900, "category": "Street", "engineCapacity": 1000 }
- Deve-se retornar um JSON com as seguintes chaves:
03 - Rota /motorcycles/:id onde seja possível atualizar uma moto por ID
Detalhes
- 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.000,
"category": "Street",
"engineCapacity": 600
}
Os seguintes pontos foram 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.000, "category": "Street", "engineCapacity": 600 }
Testes
-
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
; -
Execute o comando
test:coverage
; para analisar cobertura total das linhas; -
Só será contabilizada a cobertura, se seus testes não conterem erros.
01- Escreva testes para cobrir 30% da camada de Service
Detalhes
- 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%;
02- Escreva testes para cobrir 60% da camada de Service
Detalhes
- 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%;
03- Escreva testes para cobrir 80% da camada de Service
Detalhes
- 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%;
04- Cobertura total das linhas dos arquivos da camada Services
é maior ou igual a 100%;
Gostaria de expressar minha profunda gratidão aos monitores e à Trybe por todo o suporte e orientação ao longo do projeto. Sua dedicação, conhecimento e disposição em ajudar foram fundamentais para o meu aprendizado e crescimento profissional. Sou grato pela oportunidade de fazer parte dessa comunidade de aprendizagem e por todo o apoio recebido durante essa jornada.