Esse é um projeto de aprendizado de aplicação de conceitos de construção de camadas Model, Services e Controllers. O projeto trata-se de uma API de um sistema de gerenciamento de vendas, onde é possível criar, listar, atualizar e deletar produtos e vendas (CRUD).
- Entender o funcionamento da camada de Model;
- Delegar responsabilidades específicas para essa camada;
- Conectar sua aplicação com diferentes bancos de dados;
- Estruturar uma aplicação em camadas;
- Delegar responsabilidades específicas para cada parte do seu app;
- Melhorar manutenibilidade e reusabilidade do seu código;
- Entender e aplicar os padrões REST;
- Escrever assinaturas para APIs intuitivas e facilmente entendíveis.
Para conectar corretamente a API ao banco SQL, as variáveis de ambiente foram configuradas no arquido .env na raiz do projeto.
MYSQL_HOST=localhost
MYSQL_USER=nome
MYSQL_PASSWORD=1234
PORT=3000
Para instalar o projeto localmente
- Clone o projeto
git clone git@github.com:MikaelaBraga/store-manager.git- Acesse a pasta do projeto
cd store-manager- Instale as dependências
npm install- Execute o projeto (utilize algum cliente para testar as rotas: insomnia, postman, etc...)
npm start- Execute os testes
npm run test:mocha POST /products| Parameter | Type | Description |
|---|---|---|
name |
string |
Required |
quantity |
string |
Required |
GET /products [
{
"id": 1,
"name": "produto A",
"quantity": 10
},
{
"id": 2,
"name": "produto B",
"quantity": 20
}
]
GET /products/${id}| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Id of item to fetch |
PUT /products/${id}| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Id of item to update |
DELETE /products/${id}| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Id of item to delete |
POST /sales| Parameter | Type | Description |
|---|---|---|
product_id |
string |
Required |
quantity |
string |
Required |
GET /sales[
{
"saleId": 1,
"date": "2021-09-09T04:54:29.000Z",
"product_id": 1,
"quantity": 2
},
{
"saleId": 1,
"date": "2021-09-09T04:54:54.000Z",
"product_id": 2,
"quantity": 2
}
]
GET /sales/${id}| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Id of sale to fetch |
PUT /sales/${id}| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Id of sale to update |
DELETE /sales/${id}| Parameter | Type | Description |
|---|---|---|
id |
string |
Required. Id of sale to delete |
Lista de requisitos
-
O endpoint deve ser acessível através do caminho (
/products); -
Os produtos enviados devem ser salvos na tabela
productsdo Banco de Dados; -
O endpoint deve receber a seguinte estrutura:
{
"name": "product_name",
"quantity": "product_quantity"
}O que será validado
👉 Para o endpoint
POST /products, o camponamedeve ser uma string com 5 ou mais caracteres e deve ser único.
-
Quando a requisição é feita sem o atributo
name:{ "quantity": 100 }- sua API deve responder com status http
400e o seguintebody:
{ "message": "\"name\" is required" } - sua API deve responder com status http
-
Quando a requisição é feita e contém o seguinte
body:{ "name": "pro", "quantity": 100 }- sua API deve responder com status http
422e o seguintebody:
{ "message": "\"name\" length must be at least 5 characters long" } - sua API deve responder com status http
-
Quando a requisição é feita com o atributo
nameigual um já cadastrado:{ "name": "produto", "quantity": 100 }- sua API deve responder com status http
409e o seguintebody:
{ "message": "Product already exists" } - sua API deve responder com status http
👉 Para o endpoint
POST /products, o campoquantitydeve ser um número inteiro maior que 0.
-
Quando a requisição é feita sem o atributo
quantity:{ "name": "produto" }- sua API deve responder com status http
400e o seguintebody:{ "message": "\"quantity\" is required" }
- sua API deve responder com status http
-
Quando a requisição é feita e contém os seguintes
body:{ "name": "produto", "quantity": "string" }{ "name": "produto", "quantity": -1 }{ "name": "produto", "quantity": 0 }- sua API deve responder com status http
422e o seguintebody:
{ "message": "\"quantity\" must be a number larger than or equal to 1" } - sua API deve responder com status http
👉 Para o endpoint
POST /products, quando a requisição é feita corretamente, o produto deve ser cadastrado.
- Quando a requisição é feita e contém o seguinte
body:{ "name": "produto", "quantity": 10 }- sua API deve responder com status http
201e o seguintebody:
{ "id": 1, "name": "produto", "quantity": 10 } - sua API deve responder com status http
-
O endpoint deve ser acessível através do caminho (
/products) ou (/products/:id); -
Através do caminho
/products, todos os produtos devem ser retornados; -
Através do caminho
/products/:id, apenas o produto com oidpresente na URL deve ser retornado;
O que será validado
👉 Para o endpoint
GET /products, será validado que todos produtos estão sendo retornados.
- sua API deve responder com status http
200e o seguintebody:
[
{
"id": 1,
"name": "produto A",
"quantity": 10
},
{
"id": 2,
"name": "produto B",
"quantity": 20
}
]👉 Para o endpoint
GET /products/:id, será validado que é possível listar um determinado produto.
- sua API deve responder com status http
200e o seguintebody:{ "id": 1, "name": "produto A", "quantity": 10 }
👉 Para o endpoint
GET /products/:id, será validado que não é possível listar um produto que não existe.
- sua API deve responder com status http
404e o seguintebody:{ "message": "Product not found" }
-
O endpoint deve ser acessível através do caminho (
/products/:id); -
O corpo da requisição deve seguir a mesma estrutura do método responsável por adicionar um produto;
-
Apenas o produto com o
idpresente na URL deve ser atualizado; -
O corpo da requisição deve receber a seguinte estrutura:
{
"name": "new_product_name",
"quantity": "new_product_quantity"
}O que será validado
👉 Para o endpoint
PUT /products/:id, o camponamedeve ser uma string com 5 ou mais caracteres e deve ser único.
- Quando a requisição é feita e contém o seguinte
body:{ "name": "pro", "quantity": 15 }- sua API deve responder com status http
422e o seguintebody:
{ "message": "\"name\" length must be at least 5 characters long" } - sua API deve responder com status http
👉 Para o endpoint
PUT /products/:id, o campoquantitydeve ser um número inteiro maior que 0.
- Quando a requisição é feita e contém os seguintes
body:{ "name": "produto", "quantity": "string" }{ "name": "produto", "quantity": -1 }{ "name": "produto", "quantity": 0 }- sua API deve responder com status http
422e o seguintebody:
{ "message": "\"quantity\" must be a number larger than or equal to 1" } - sua API deve responder com status http
👉 Para o endpoint
PUT /products/:id, quando a requisição é feita corretamente, o produto deve ser alterado.
- Quando a requisição é feita e contém o seguinte
body:{ "name": "produto", "quantity": 15 }- sua API deve responder com status http
200e o seguintebody:
{ "id": 1, "name": "produto", "quantity": 15 } - sua API deve responder com status http
👉 Para o endpoint
PUT /products/:id, será validado que não é possível alterar um produto que não existe.
- sua API deve responder com status http
404e o seguintebody:{ "message": "Product not found" }
-
O endpoint deve ser acessível através do caminho (
/products/:id); -
Apenas o produto com o
idpresente na URL deve ser deletado;
O que será validado
👉 Para o endpoint
DELETE /products/:id, será validado que é possível deletar um produto com sucesso.
- sua API deve responder com status http
200e o seguintebody:
{
"id": 1,
"name": "produto A",
"quantity": 10
}👉 Para o endpoint
DELETE /products/:id, será validado que não é possível deletar um produto que não existe.
- sua API deve responder com status http
404e o seguintebody:{ "message": "Product not found" }
-
O endpoint deve ser acessível através do caminho (
/sales); -
As vendas enviadas devem ser salvas na tabela
salesesales_productsdo Banco de dados; -
Deve ser possível cadastrar a venda de vários produtos através da uma mesma requisição;
-
O endpoint deve receber a seguinte estrutura:
[
{
"product_id": "product_id",
"quantity": "product_quantity",
}
]O que será validado
👉 Para o endpoint
POST /sales, o campoproduct_iddeve ser um id de um produto anteriormente cadastrado.
- Quando a requisição é feita sem o atributo
product_id:[ { "quantity": 1 } ]- sua API deve responder com status http
400e o seguintebody:
{ "message": "\"product_id\" is required" } - sua API deve responder com status http
👉 Para o endpoint
POST /sales, o campoquantitydeve ser um número inteiro maior que 0.
-
Quando a requisição é feita sem o atributo
quantity:[ { "product_id": 1 } ]- sua API deve responder com status http
400e o seguintebody:{ "message": "\"quantity\" is required" }
- sua API deve responder com status http
-
Quando a requisição é feita e contém os seguintes
body:[ { "product_id": 1, "quantity": -1 } ][ { "product_id": 1, "quantity": 0 } ][ { "product_id": 1, "quantity": "string" } ]- sua API deve responder com status http
422e o seguintebody:
{ "message": "\"quantity\" must be a number larger than or equal to 1" } - sua API deve responder com status http
👉 Para o endpoint
POST /sales, quando a requisição é feita corretamente, o produto deve ser cadastrado.
- Quando a requisição é feita e contém o seguinte
body:[ { "product_id": 1, "quantity": 3 } ]- sua API deve responder com status http
201e o seguintebody:
{ "id": 1, "itemsSold": [ { "product_id": 1, "quantity": 3 } ] } - sua API deve responder com status http
👉 Para o endpoint
POST /sales, quando a requisição é feita corretamente, a venda deve ser cadastrada.
- Quando a requisição é feita e contém o seguinte
body:[ { "product_id": 1, "quantity": 2 }, { "product_id": 2, "quantity": 5 } ]- sua API deve responder com status http
201e o seguintebody:
{ "id": 1, "itemsSold": [ { "product_id": 1, "quantity": 2 }, { "product_id": 2, "quantity": 5 } ] } - sua API deve responder com status http
-
O endpoint deve ser acessível através do caminho (
/sales) ou (/sales/:id); -
Através do caminho
/sales, todas as vendas devem ser retornadas; -
Através do caminho
/sales/:id, apenas a venda com oidpresente na URL deve ser retornada;
O que será validado
👉 Para o endpoint
GET /sales, será validado que todas vendas estão sendo retornados.
- sua API deve responder com status http
200e o seguintebody:
[
{
"saleId": 1,
"date": "2021-09-09T04:54:29.000Z",
"product_id": 1,
"quantity": 2
},
{
"saleId": 1,
"date": "2021-09-09T04:54:54.000Z",
"product_id": 2,
"quantity": 2
}
]👉 Para o endpoint
GET /sales/:id, será validado que é possível listar uma determinada venda.
- sua API deve responder com status http
200e o seguintebody:[ { "date": "2021-09-09T04:54:29.000Z", "product_id": 1, "quantity": 2 }, { "date": "2021-09-09T04:54:54.000Z", "product_id": 2, "quantity": 2 } ]
👉 Para o endpoint
GET /sales/:id, será validado que não é possível listar uma venda que não existe.
- sua API deve responder com status http
404e o seguintebody:{ "message": "Sale not found" }
-
O endpoint deve ser acessível através do caminho (
/sales/:id); -
quantitydeve ser um número inteiro maior que 0; -
Apenas a venda com o
idpresente na URL deve ser atualizada; -
O corpo da requisição deve receber a seguinte estrutura:
[
{
"product_id": "id_change",
"quantity": "new_quantity"
}
]O que será validado
👉 Para o endpoint
PUT /sales/:id, o campoproduct_iddeve ser um id de um produto anteriormente cadastrado.
- Quando a requisição é feita sem o atributo
product_id:[ { "quantity": 10 } ]- sua API deve responder com status http
400e o seguintebody:
{ "message": "\"product_id\" is required" } - sua API deve responder com status http
👉 Para o endpoint
PUT /sales/:id, o campoquantitydeve ser um número inteiro maior que 0.
-
Quando a requisição é feita sem o atributo
quantity:[ { "product_id": 1 } ]- sua API deve responder com status http
400e o seguintebody:
{ "message": "\"quantity\" is required" } - sua API deve responder com status http
-
Quando a requisição é feita e contém os seguintes
body:[ { "product_id": 1, "quantity": -1 } ][ { "product_id": 1, "quantity": 0 } ][ { "product_id": 1, "quantity": "string" } ]- sua API deve responder com status http
422e o seguintebody:
{ "message": "\"quantity\" must be a number larger than or equal to 1" } - sua API deve responder com status http
👉 Para o endpoint
PUT /sales/:id, quando a requisição é feita corretamente, a venda deve ser alterada.
- Quando a requisição é feita e contém o seguinte
body:[ { "product_id": 1, "quantity": 6 } ]- sua API deve responder com status http
200e o seguintebody:
{ "saleId": 1, "itemUpdated": [ { "product_id": 1, "quantity": 6 } ] } - sua API deve responder com status http
-
Seus arquivos de teste devem ficar no diretório
test/unit, como citado aqui; -
Seus testes da
modeldevem fazer mock do banco de dados obrigatóriamente; -
Opcionalmente você pode parar o serviço do
MYSQLem sua máquina. Para rodar seus teste utilizenpm run test:mocha;
O que será validado
👉 Será validado que a cobertura total das linhas dos arquivos nas pastas
models,servicesecontrollersé maior ou igual a 35%.
👉 Será validado que ao menos 24 linhas são cobertas pelos testes.
-
Seus arquivos de teste devem ficar no diretório
test/unit, como citado aqui -
Seus testes da
modeldevem fazer mock do banco de dados obrigatóriamente; -
Opcionalmente você pode parar o serviço do
MYSQLem sua máquina. Para rodar seus teste utilizenpm run test:mocha;
O que será validado
👉 Será validado que a cobertura total das linhas dos arquivos nas pastas
models,servicesecontrollersé maior ou igual a 40%.
👉 Será validado que ao menos 24 linhas são cobertas pelos testes.
-
O endpoint deve ser acessível através do caminho (
/sales/:id); -
Apenas a venda com o
idpresente na URL deve ser deletado;
O que será validado
👉 Para o endpoint
DELETE /sales/:id, será validado que é possível deletar uma venda com sucesso.
- sua API deve responder com status http
200e o seguintebody:
[
{
"date": "2021-09-09T04:54:29.000Z",
"product_id": 1,
"quantity": 2
},
{
"date": "2021-09-09T04:54:54.000Z",
"product_id": 2,
"quantity": 2
}
]👉 Para o endpoint
DELETE /sales/:id, será validado que não é possível deletar uma venda que não existe.
- sua API deve responder com status http
404e o seguintebody:
{ "message": "Sale not found" }-
Ao realizar uma venda, atualizá-la ou deletá-la, você deve também atualizar a quantidade do produto em questão presente na tabela responsável pelos produtos;
- Exemplo 1: suponha que haja um produto chamado Bola de Futebol e a sua propriedade
quantitytenha o valor 10. Caso seja feita uma venda com 8 unidades desse produto, a quantidade do produto deve ser atualizada para 2 , pois 10 - 8 = 2; - Exemplo 2: Suponha que esta venda tenha sido deletada, logo estas 8 unidades devem voltar ao
quantitye seu valor voltará a 10, pois 2 + 8 = 10;
- Exemplo 1: suponha que haja um produto chamado Bola de Futebol e a sua propriedade
O que será validado
👉 Será validado que ao fazer uma determinada venda, a quantidade do produto deverá ser atualizada também na tabela responsável pelos produtos.
👉 Será validado que ao deletar uma determinada venda, a quantidade do produto deverá ser atualizada também na tabela responsável pelos produtos;.
-
Um produto nunca deve ter a quantidade em estoque menor que 0;
-
Quando uma venda for realizada, garanta que a quantidade sendo vendida está disponível no estoque
O que será validado
👉 Para o endpoint
POST /sales, será validado que a quantidade de produtos em estoque nunca seja menor que 0 (zero).
- Quando a requisição é feita com uma quantidade superior a quantidade em estoque:
[ { "product_id": 1, "quantity": 100 } ]- sua API deve responder com status http
422e o seguintebody:
{ "message": "Such amount is not permitted to sell" } - sua API deve responder com status http
-
Seus arquivos de teste devem ficar no diretório
test/unit, como citado aqui; -
Seus testes da
modeldevem fazer mock do banco de dados obrigatóriamente; -
Opcionalmente você pode parar o serviço do
MYSQLem sua máquina. Para rodar seus teste utilizenpm run test:mocha;
O que será validado
👉 Será validado que a cobertura total das linhas dos arquivos nas pastas
models,servicesecontrollersé maior ou igual a 50%.
👉 Será validado que ao menos 24 linhas são cobertas pelos testes.
-
Seus arquivos de teste devem ficar no diretório
test/unit, como citado aqui; -
Seus testes da
modeldevem fazer mock do banco de dados obrigatóriamente; -
Opcionalmente você pode parar o serviço do
MYSQLem sua máquina. Para rodar seus teste utilizenpm run test:mocha;
O que será validado
👉 Será validado que a cobertura total das linhas dos arquivos nas pastas
models,servicesecontrollersé maior ou igual a 60%.
👉 Será validado que ao menos 24 linhas são cobertas pelos testes.