O Store Manager é uma API RESTful desenvolvida para o gerenciamento de vendas e produtos de uma loja. O sistema permite criar, visualizar, deletar e atualizar produtos e vendas.
O projeto foi construído utilizando a arquitetura MSC (Model-Service-Controller), garantindo a segregação de responsabilidades, testabilidade e manutenibilidade do código.
- Node.js & Express: Para construção da API.
- MySQL: Banco de dados relacional.
- Docker: Para containerização da aplicação e do banco de dados.
- Mocha, Chai & Sinon: Para testes unitários.
- Joi: Para validação de dados (Middlewares).
O projeto segue a arquitetura em camadas (Layered Architecture):
- Model: Acesso direto ao banco de dados (MySQL).
- Service: Regras de negócio e validações lógicas.
- Controller: Interface com a requisição HTTP (Request/Response).
A estrutura do banco consiste nas tabelas products, sales e a tabela de associação sales_products.
- Products: Armazena os produtos (
id,name). - Sales: Armazena a data da venda (
id,date). - Sales_Products: Relacionamento N:N, armazenando a quantidade vendida de cada produto em cada venda.
- Docker e Docker Compose instalados.
-
Clone o repositório:
git clone git@github.com:Matheus-Pozett/API-Store-Manager.git cd API-Store-Manager -
Instale as dependências:
npm install
-
Suba os containers (Aplicação + Banco):
docker-compose up -d
-
Acesse a API: O servidor estará rodando em
http://localhost:3001.
O projeto possui ampla cobertura de testes unitários para garantir a confiabilidade das camadas Model, Service e Controller.
Para rodar os testes:
npm test| Método | Funcionalidade | URL |
|---|---|---|
GET |
Retorna uma lista de produtos cadastrados | http://localhost:3001/products |
A resposta da requisição é a seguinte, com status 200:
[
{
"id": 1,
"name": "Martelo de Thor"
},
{
"id": 2,
"name": "Traje de encolhimento"
},
{
"id": 3,
"name": "Escudo do Capitão América"
}
]| Método | Funcionalidade | URL |
|---|---|---|
GET |
Retorna um produto pelo id (substitua :id por um número) |
http://localhost:3001/products/:id |
A resposta da requisição é a seguinte, com status 200:
{
"id": 1,
"name": "Martelo de Thor"
}A requisição irá falhar nos seguintes casos:
- A rota retorna o código404, com a mensagem Product not found caso tente acessar um id não existente no banco.| Método | Funcionalidade | URL |
|---|---|---|
POST |
Insere um novo produto no banco de dados | http://localhost:3001/products |
A estrutura do body da requisição deverá seguir o padrão abaixo:
{
"name": "ProdutoX"
}A resposta da requisição é a seguinte, com status 201:
{
"id": 4,
"name": "ProdutoX"
}A requisição irá falhar nos seguintes casos:
- A rota retorna o código400, com a mensagem "name" is required caso o campo name não seja informado no body da requisição;- A rota retorna o código
422, com a mensagem "name" length must be at least 5 characters long caso o campo name tenha menos de 5 caracteres no body da requisição.| Método | Funcionalidade | URL |
|---|---|---|
PUT |
Atualiza um produto no banco de dados pelo seu id (substitua :id por um número) |
http://localhost:3001/products/:id |
A estrutura do body da requisição deverá seguir o padrão abaixo:
{
"name": "Martelo do Batman"
}A resposta da requisição é a seguinte, com status 200:
{
"id": 1,
"name": "Martelo do Batman"
}A requisição irá falhar nos seguintes casos:
- A rota retorna o código400, com a mensagem "name" is required caso o campo name não seja informado no body da requisição;- A rota retorna o código
422, com a mensagem "name" length must be at least 5 characters long caso o campo name tenha menos de 5 caracteres no body da requisição;- A rota retorna o código
404, com a mensagem Product not found caso tente acessar um id não existente no banco.| Método | Funcionalidade | URL |
|---|---|---|
DELETE |
Remove um produto do banco de dados (substitua :id por um número) |
http://localhost:3001/products/:id |
A rota retorna o status 204, sem resposta.
A requisição irá falhar nos seguintes casos:
- A rota retorna o código404, com a mensagem Product not found caso tente acessar um id não existente no banco.| Método | Funcionalidade | URL |
|---|---|---|
GET |
Retorna uma lista de produtos com base em um filtro (substitua searchTerm pelo nome do produto) |
http://localhost:3001/products/search?q=searchTerm |
A resposta da requisição é a seguinte, com status 200:
// GET /products/search?q=Martelo
[
{
"id": 1,
"name": "Martelo de Thor",
}
]| Método | Funcionalidade | URL |
|---|---|---|
GET |
Retorna uma lista de vendas cadastradas | http://localhost:3001/sales |
A resposta da requisição é a seguinte, com status 200:
[
{
"saleId": 1,
"productId": 1,
"quantity": 5,
"date": "2022-10-25T21:03:44.000Z"
},
{
"saleId": 1,
"productId": 2,
"quantity": 10,
"date": "2022-10-25T21:03:44.000Z"
},
{
"saleId": 2,
"productId": 3,
"quantity": 15,
"date": "2022-10-25T21:03:44.000Z"
}
]| Método | Funcionalidade | URL |
|---|---|---|
GET |
Retorna uma venda pelo id (substitua id por um número) |
http://localhost:3001/sales/:id |
A resposta da requisição é a seguinte, com status 200:
[
{
"productId": 1,
"quantity": 5,
"date": "2022-10-25T21:03:44.000Z"
},
{
"productId": 2,
"quantity": 10,
"date": "2022-10-25T21:03:44.000Z"
}
]| Método | Funcionalidade | URL |
|---|---|---|
POST |
Adiciona uma venda no banco de dados | http://localhost:3001/sales |
A estrutura do body da requisição deverá seguir o padrão abaixo:
[
{
"productId": 1,
"quantity": 1
},
{
"productId": 2,
"quantity": 5
}
]A resposta da requisição é a seguinte, com status 201:
{
"id": 3,
"itemsSold": [
{
"productId": 1,
"quantity": 1
},
{
"productId": 2,
"quantity": 5
}
]
}A requisição irá falhar nos seguintes casos:
- A rota retorna o código400, com a mensagem "productId" is required caso algum dos itens na lista de vendas não possua o campo productId no body da requisição;- A rota retorna o código
400, com a mensagem "quantity" is required caso algum dos itens na lista de vendas não possua o campo quantity no body da requisição;- A rota retorna o código
422, com a mensagem "quantity" must be greater than or equal to 1 caso algum dos itens na lista de vendas possua o campo quantity com valor abaixo de 1 no body da requisição;- A rota retorna o código
404, com a mensagem Product not found caso tente acessar um id não existente no banco.| Método | Funcionalidade | URL |
|---|---|---|
PUT |
Atualiza uma venda no banco de dados (substitua id por um número) |
http://localhost:3001/sales/:saleId/products/:productId/quantity |
A estrutura do body da requisição deverá seguir o padrão abaixo:
{
"quantity": 10
}A resposta da requisição é a seguinte, com status 200:
{
"saleId": 1,
"productId": 2,
"quantity": 20,
"date": "2023-05-06T03:14:28.000Z"
}A requisição irá falhar nos seguintes casos:
- A rota retorna o código400, com a mensagem "productId" is required caso algum dos itens na lista de vendas não possua o campo productId no body da requisição;- A rota retorna o código
400, com a mensagem "quantity" is required caso algum dos itens na lista de vendas não possua o campo quantity no body da requisição;- A rota retorna o código
400, com a mensagem "quantity" must be greater than or equal to 1 caso algum dos itens na lista de vendas possua o campo quantity com valor abaixo de 1 no body da requisição;- A rota retorna o código
404, com a mensagem Sale not found caso tente acessar um id não existente no banco.| Método | Funcionalidade | URL |
|---|---|---|
DELETE |
Remove uma venda do banco de dados (substitua :id por um número) |
http://localhost:3001/sales/:id |
A rota retorna o status 204, sem resposta.
A requisição irá falhar nos seguintes casos:
- A rota retorna o código404, com a mensagem Sale not found caso tente acessar um id não existente no banco.Desenvolvido 💚 por Matheus Pozett