/api-control-stock

Esse projeto consiste em uma api para uma aplicação que tem como foco registrar as entradas e saídas de produtos e efetuar o controle de estoque.

Primary LanguageTypeScript

Api para controle de estoque/entrada e saída de produtos

Uma api que tem como objetivo automatizar uma tarefa super repetitiva, a saída e entrada dos produtos de uma loja. Além disso, fornece também o recurso de controle de estoque, que é calculado a partir do momento que uma entrada é registrada para tal produto.

A criação da API é feita com o Express, utilizando o ORM Prisma para efetuar as queries no PostgreSQL.

Todos os dados são validados com a biblioteca Zod, as senhas registradas são criptografadas com bcrypt, e além disso, o token JWT é utilizado para autenticação.

Nesse projeto foi implementado o padrão Either (estrutura de dados que representa dois tipos diferentes, Success e Failure), facilitando a manipulação e tratativa dos erros da aplicação.

Para finalizar, são feito alguns testes unitários com o Vitest.

Tópicos 📍

Melhorias feitas 🧰

  • Criação de lojas no sistema
  • Autenticação com JWT
  • Linkagem dos produtos com uma única loja

Tecnologias Utilizadas 🖥️

Como rodar esse projeto? 💿

Pre-requisitos

Clonagem

# clone o repositório
$ git clone https://github.com/bastosmatheus/api-control-stock

Configuração do arquivo .env

# arquivo .env
DATABASE_URL="postgresql://username:password@localhost:5432/yourdatabase?schema=public"

Projeto

# depois de clonado, procure a pasta do projeto
$ cd api-control-stock

# instale todas as dependências
$ npm install

# execute o projeto
$ npm run start

Principais endpoints da API 🗺️

ROUTE DESCRIPTION
RESPOSTAS DE SUCESSO
POST /products cria um produto, veja mais na resposta da requisição
POST /entrances cria uma entrada para determinado produto, veja detalhes da requisição
POST /exits informa uma saída de um produto, veja mais na resposta da requisição
POST /devolutions registra detalhes da devolução de um produto, veja detalhes da requisição
POST /defectiveproducts registra detalhes de um produto defeituoso, veja mais na resposta da requisição
POST /stores cria uma loja, veja detalhes da requisição
GET /products/:id retorna todos os produtos registrado na API, veja resposta da requisição
RESPOSTAS COM ERROS
GET /products/:idInexistente erro ao passar um id inexistente para o get, veja mais na resposta da requisição
POST /products falha ao tentar registrar um produto que já existe no banco de dados, veja mais na resposta da requisição
PUT /entrances/:id erro ao passar um id de produto errado, veja mais na resposta da requisição
PUT /exits/:id falha ao passar um tipo errado da descrição, veja mais na resposta da requisição
POST /defectiveproducts erro ao tentar registrar um produto defeituoso sem um campo obrigatório, veja mais na resposta da requisição

Respostas de sucesso

POST /products

Ao criar uma loja (store), o usuário recebe um token de autenticação JWT, que é necessário para fazer as requisições de criação, atualização e deleção de produtos (products).

REQUISIÇÃO

{
  "name_product": "Barra de cereal",
  "price_product": 2.4,
  "id_store": 1
}

RESPOSTA

{
  "message": "Produto criado com sucesso",
  "type": "OK",
  "statusCode": 200,
  "productCreated": {
    "id": 3,
    "name_product": "Barra de cereal",
    "price_product": 2.4,
    "quantity_product_stock": 0,
    "id_store": 1
  }
}

POST /entrances

REQUISIÇÃO

{
  "supplier": "maTheus fornecedor",
  "quantity_products": 200,
  "price_total": 480,
  "id_product": 3
}

RESPOSTA

{
  "message": "Entrada criada com sucesso",
  "type": "OK",
  "statusCode": 200,
  "entranceCreated": {
    "id": 17,
    "supplier": "maTheus fornecedor",
    "quantity_products": 200,
    "price_total": 480,
    "entrance_date": "2024-03-18T00:00:00.000Z",
    "id_product": 3
  }
}

POST /exits

REQUISIÇÃO

{
  "description": "Usuário comprou uma barra de cereal",
  "quantity_products": 1,
  "price_total": 2.4,
  "id_product": 3
}

RESPOSTA

{
  "message": "Saída criada com sucesso",
  "type": "OK",
  "statusCode": 200,
  "exitCreated": {
    "id": 11,
    "description": "Usuário comprou uma barra de cereal",
    "quantity_products": 1,
    "price_total": 2.4,
    "exit_date": "2024-03-18T00:00:00.000Z",
    "id_product": 3
  }
}

POST /devolutions

REQUISIÇÃO

{
  "description": "Barra de cereal veio quebrada",
  "quantity_products": 1,
  "id_entrance": 17
}

RESPOSTA

{
  "message": "Devolução criada com sucesso",
  "type": "OK",
  "statusCode": 200,
  "devolutionCreated": {
    "id": 3,
    "description": "Barra de cereal veio quebrada",
    "quantity_products": 1,
    "devolution_date": "2024-03-18T00:00:00.000Z",
    "id_entrance": 17
  }
}

POST /defectiveproducts

REQUISIÇÃO

{
  "description": "Barra de cereal com bixinhos dentro",
  "quantity_products": 1,
  "id_entrance": 17
}

RESPOSTA

{
  "message": "Produto com defeito criado com sucesso",
  "type": "OK",
  "statusCode": 200,
  "defectiveProductCreated": {
    "id": 5,
    "description": "Barra de cereal com bixinhos dentro",
    "quantity_products": 1,
    "id_entrance": 17
  }
}

POST /stores

REQUISIÇÃO

{
  "name_store": "mtCompany",
  "email": "mthscompany@gmail.com",
  "password": "102030"
}

RESPOSTA

{
  "message": "Loja criada com sucesso",
  "type": "Created",
  "statusCode": 201,
  "storeCreated": {
    "id": 5,
    "name_store": "mtCompany",
    "email": "mthscompany@gmail.com",
    "password": "$2b$10$l/YKKyezrYU/18RjG7cxlOjl1HWaLH/neDz4.hFmJhQAYEBofcI/2",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lX3N0b3JlIjoibXRDb21wYW55IiwiaWQiOjUsImlhdCI6MTcxMzM5MDkwNCwiZXhwIjoxNzE1OTgyOTA0fQ.1K7qHrdMuJdlZ3xSpYbsN2ub9s-DCZ6wg-hMUVFX8l8"
  }
}

GET /products/:id

RESPOSTA

{
  "type": "OK",
  "statusCode": 200,
  "product": {
    "id": 3,
    "name_product": "Barra de ceral",
    "price_product": 2.4,
    "quantity_product_stock": 280,
    "id_store": 1,
    "entrance": [
      {
        "id": 17,
        "supplier": "maTheus fornecedor",
        "quantity_products": 1,
        "price_total": 2.4,
        "entrance_date": "2024-03-18T00:00:00.000Z",
        "id_product": 3,
        "defective_product": [
          {
            "id": 5,
            "description": "Barra de cereal com bixinhos dentro",
            "quantity_products": 1,
            "id_entrance": 17
          }
        ],
        "devolution": [
          {
            "id": 3,
            "description": "Barra de cereal veio quebrada",
            "quantity_products": 1,
            "devolution_date": "2024-03-18T00:00:00.000Z",
            "id_entrance": 17
          }
        ]
      }
    ],
    "exit": [
      {
        "id": 11,
        "description": "Usuário comprou uma barra de cereal",
        "quantity_products": 1,
        "price_total": 2.4,
        "exit_date": "2024-03-18T00:00:00.000Z",
        "id_product": 3
      }
    ]
  }
}

Respostas com erros

Além dessas respostas de sucesso, a API também conta com algumas respostas informando erros, tanto de requisições, quanto de regras de negócio, veja agora:

GET /products/:idInexistente

RESPOSTA

{
  "message": "Nenhum produto foi encontrado com o ID: {idInexistente}",
  "type": "Not Found",
  "statusCode": 404
}

POST /products

REQUISIÇÃO

{
  "name_product": "Barra de cereal",
  "price_product": 2.4,
  "id_store": 1
}

RESPOSTA

{
  "message": "Já existe um produto com esse nome: Barra de cereal",
  "type": "Conflict",
  "statusCode": 409
}

PUT /entrances/:id

REQUISIÇÃO

{
    "supplier": "maTheus fornecedor",
    "quantity_products": 1,
    "price_total": 2.4,
    "id_product": {id_productInexistente}
}

RESPOSTA

{
  "message": "Nenhum produto foi encontrado com o ID: {id_productInexistente}",
  "type": "Not Found",
  "statusCode": 404
}

PUT /exits/:id

REQUISIÇÃO

{
  "description": null,
  "quantity_products": 1,
  "price_total": 2.4,
  "id_product": 3
}

RESPOSTA

{
  "message": "A descrição da saída do(s) produto(s) deve ser uma string",
  "type": "Unprocessable Entity",
  "statusCode": 422
}

POST /defectiveproducts

REQUISIÇÃO

{
  "quantity_products": 1,
  "id_entrance": 17
}

RESPOSTA

{
  "message": "Informe o defeito desse produto",
  "type": "Unprocessable Entity",
  "statusCode": 422
}