Consiste em uma API HTTP (JSON) de e-commerce (venda online) e tem um endpoint de carrinho (checkout). Esse endpoint aceitará uma requisição com método POST, a estrutura do payload de requisição que segue o exemplo:
Em resumo a requisição deve conter uma lista de produtos e a quantidade de cada um a ser comprado.
{
"products": [
{
"id": 1,
"quantity": 1 // Quantidade a ser comprada do produto
}
]
}
A API conta com as seguintes regras de negócio:
-
Para cada produto é calculada a porcentagem de desconto e isso é feito consumindo um serviço gRPC fornecido pela Hash, disponível em uma imagem Docker e o cliente foi gerado em Javascript a partir do arquivo proto
-
Caso o serviço de desconto esteja indisponível o endpoint de carrinho deverá continuar funcionando porém não vai realizar o cálculo com desconto.
-
É verificado se é black friday e caso seja, um produto brinde pode ser adicionado no carrinho. No arquivo products.json eles estão marcados com a flag
is_gift = true
e não são aceitos em requisições para adicioná-los ao carrinho. A data da Black Friday pode ser configurada através de um arquivo .env, um arquivo exemplo foi anexado ao repositório para verificação de como setar as variáveis de ambiente. -
Há apenas uma entrada de produto brinde no carrinho.
Abaixo segue um exemplo de resposta com status HTTP 200 da API:
{
"total_amount": 20000, // Valor total da compra sem desconto
"total_amount_with_discount": 19500, // Valor total da compra com desconto
"total_discount": 500, // Valor total de descontos
"products": [
{
"id": 1,
"quantity": 2,
"unit_amount": 10000, // Preço do produto em centavos
"total_amount": 20000, // Valor total na compra desse produto em centavos
"discount": 500, // Valor total de desconto em centavos
"is_gift": false // É brinde?
},
{
"id": 3,
"quantity": 1,
"unit_amount": 0, // Preço do produto em centavos
"total_amount": 0, // Valor total na compra desse produto em centavos
"discount": 0, // Valor total de desconto em centavos
"is_gift": true // É brinde?
}
]
}
- Node.js
- Scripts de teste na API foram escritos através do framework Jest
- Docker
- Docker-Compose
- NPM 8.5 ou superior
- Node 12.22 ou superior
- Docker 19.x ou superior
- Docker-Compose 1.26 ou superior
git clone https://github.com/felipedmsantos95/cart-gRPC-api
cd cart-gRPC-api
Considerando que os requisitos para rodar a aplicação estejam satisfeitos, podemos executar os seguintes comandos:
Antes de execução dos comandos docker, precisamos configurar um .env
na raiz do projeto, as variáveis devem ser configuradas seguindo o exemplo
touch .env
Modelo de conteúdo do arquivo:
# --------- #
## GENERAL ##
# --------- #
PROJECT_NAME=hash-cart-challenge
# You can change to run API in another HTTP port
API_PORT=3000
# --------- #
## gRPC ##
# --------- #
#If it is running in your local machine, please input IP address of your machine
GRPC_SERVER_ADDRESS=your_ip_server_address:50051
# -------------------#
## Bussiness Rules ##
# ------------------ #
# Date format ==> year/month/day
BLACK_FRIDAY_DAY=2022/02/16
Para baixar as imagens docker necessárias e executar os containers com a API e o serviço de desconto da Hash:
docker-compose up
Essa deve ser a sáida do terminal e a API estará pronta para receber requisições:
npm install
Executar serviço:
npm start
Executar serviço com reinício automático se for detectada alteração no código:
npm run dev
Executar script de testes unitários e de integração da aplicação
npm test
docker pull hashorg/hash-mock-discount-service
docker run -p 50051:50051 hashorg/hash-mock-discount-service
POST /checkout
: A rota deve receberproducts
dentro do corpo da requisição, sendo sendo ele um array de objetos que por sua vez contém os campos numéricosid
equantity
, nesta rota também pode ser enviado nos headers a informaçãotoday_date
no formatoyyyy/mm/dd
para que o app possa comparar com o dia da Black Friday configurado no.env
, se nenhum header for enviado, o app irá comparar a data da Black Friday configurada no .env automaticamente com a data de hoje.
GET /products
: Exibe os produtos cadastrados no products.json.
Ao ter instaladas as dependências necessárias para rodar os testes, pode ser executado o comando npm test
no teminal para que sejam vistas as seguintes validações que foram escritas no arquivo cart.spec.js
-
should be able to checkout cart with valid products
: Permite que seja exibido o valor total do carrinho se a requisição for válida. -
shouldn't be able to checkout with params with invalid data type
: Não permite que o seja feito checkout se um array de produtos no formato especificado não for enviado na requisição -
shouldn't be able to checkout with invalid products
: Não permite que seja feito checkout se no carrinho houver um produto não cadastrado -
shouldn't be able to checkout with missing params
: Não permite que seja feito checkout se no corpo da requisição houver parametros faltantes -
should be able to get all products info at database
: Permite que sejam exibidos os produtos descritos em products.json -
should be able to add a gift product if it is Black Friday
: Permite que seja feito checkout de um produto com a flagis_gift
se for dia de Black Friday -
shouldn't be able to add more than one gift product input if it is Black Friday
: Não permite que seja feito checkout de mais de um produto com a flagis_gift
se for dia de Black Friday -
shouldn't be able to add more than one gift product in quantity if it is Black Friday
: Não permite que seja feito produto com a flagis_gift
com o campoquantity
maior que 1 -
shouldn't be able to add gift product if it is NOT Black Friday
: Não permite que seja feito checkout de um produto com a flagis_gift
se não for dia de Black Friday
Para validar a regra 2 no desafio proposto, onde se pede que caso o serviço de desconto esteja indisponível o endpoint de carrinho deverá continuar funcionando porém não vai realizar o cálculo com desconto, foi feito o seguinte procedimento:
- API e Serviço de desconto em execução
- Parada do serviço de desconto
- Execução do checkout
- Status 200
{
"total_amount": 223715,
"total_amount_with_discount": 221583,
"total_discount": 2132,
"products_details": [
{
"id": 5,
"quantity": 1,
"unit_amount": 42647,
"total_amount": 42647,
"discount": 2132,
"is_gift": false
},
{
"id": 3,
"quantity": 3,
"unit_amount": 60356,
"total_amount": 181068,
"discount": 0,
"is_gift": false
}
]
}
- Corpo da requisição inválido
{
"statusCode": 400,
"error": "Bad Request",
"message": "Validation failed",
"validation": {
"body": {
"source": "body",
"keys": [
"products.0.id"
],
"message": "\"id\" é um campo obrigatório"
}
}
}
- Produto brinde em uma data não Black Friday
{
"validation": {
"message": [
"O produto de id 6 é um brinde de black friday e não pode ser adicionado ao carrinho por enquanto..."
]
}
}
- Produto não cadastrado no banco de dados
{
"validation": {
"message": [
"O produto de id 50 não está cadastrado em nosso banco de dados",
"O produto de id 55 não está cadastrado em nosso banco de dados"
]
}
}
- Mais de uma entrada de produtos brinde na black friday
{
"validation": {
"message": [
"Só pode haver a quantidade de 1 produto brinde na blackfriday."
]
}
}