Skip to content

AntonioSabino/trybesmith-node

Repository files navigation

Projeto Trybesmith!

Uma loja de itens medievais, no formato de uma API, utilizando Typescript, NodeJS, Express, JWT, JOI, MySQL.

Aplicação em camadas (Models, Service e Controllers), por meio dessa aplicação, será possível realizar as operações básicas que se pode fazer em um determinado banco de dados: Criação, Leitura, Atualização e Exclusão (ou CRUD, para as pessoas mais íntimas stuck_out_tongue_winking_eye - Create, Read, Update e Delete).

CRUD em um banco de dados, utilizando o MySQL.

Orientações

🐳 Rodando no Docker vs Localmente

Com Docker

Rode os serviços node e db com o comando docker-compose up -d.

  • Lembre-se de parar o mysql se estiver usando localmente na porta padrão (3306), ou adapte, caso queria fazer uso da aplicação em containers
  • Esses serviços irão inicializar um container chamado trybesmith e outro chamado trybesmith_db.
  • A partir daqui você pode rodar o container trybesmith via CLI ou abri-lo no VS Code.

Use o comando docker exec -it trybesmith bash.

  • Ele te dará acesso ao terminal interativo do container criado pelo compose, que está rodando em segundo plano.

Instale as dependências com npm install

⚠ Atenção ⚠ Caso opte por utilizar o Docker, TODOS os comandos disponíveis no package.json (npm start, npm test, npm run dev, ...) devem ser executados DENTRO do container, ou seja, no terminal que aparece após a execução do comando docker exec citado acima.


Sem Docker

Instale as dependências com npm install

Dica: Para rodar o projeto desta forma, obrigatoriamente você deve ter o node instalado em seu computador.

🏦 Conexão com o Banco

⚠️ É essencial configurar as variáveis de ambiente para testar o projeto localmente, renomeie o arquivo .env.example para .env: ⚠️

  #### DATABASE VARS
  MYSQL_HOST=localhost
  MYSQL_USER=root
  MYSQL_PASSWORD=password

  #### SECRECT VARS
  JWT_SECRET=SecretKey

⚠️ Variáveis de ambiente além das especificadas acima não são suportadas, pois não são esperadas pelo avaliador do projeto. ⚠️

⚠️ É essencial que seu arquivo tenha o nome connection.ts e esteja no diretório src/models ⚠️

🪑 Tabelas

O banco terá três tabelas: pessoas usuárias, produtos e pedidos.

DROP SCHEMA IF EXISTS Trybesmith;
CREATE SCHEMA Trybesmith;

CREATE TABLE Trybesmith.Users (
  id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL,
  username TEXT NOT NULL,
  classe TEXT NOT NULL,
  level INTEGER NOT NULL,
  password TEXT NOT NULL
);

CREATE TABLE Trybesmith.Orders (
  id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL,
  userId INTEGER,
  FOREIGN KEY (userId) REFERENCES Trybesmith.Users (id)
);

CREATE TABLE Trybesmith.Products (
  id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL,
  name TEXT NOT NULL,
  amount TEXT NOT NULL,
  orderId INTEGER,
  FOREIGN KEY (orderId) REFERENCES Trybesmith.Orders (id)
);

Funcionalidades

1 - Endpoint para a listagem de produtos

  • O endpoint é acessível através do caminho (/products);
    • O resultado retornado para listar produtos com sucesso é conforme exibido abaixo, com um status http 200:
      [
        {
          "id": 1,
          "name": "Poção de cura",
          "amount": "20 gold",
          "orderId": null
        },
        {
          "id": 2,
          "name": "Escudo do Herói",
          "amount": "100 diamond",
          "orderId": 1
        }
      ]

2 - Endpoint para o cadastro de produtos

  • O endpoint é acessível através do caminho (/products);

  • Os produtos enviados sãp salvos na tabela Products do banco de dados;

  • O endpoint recebe a seguinte estrutura:

  {
    "name": "Espada longa",
    "amount": "30 peças de ouro"
  }
Além disso, as seguintes verificações serão feitas:

👉 Para name

  • [O campo "name" é obrigatório]

    • Se o campo "name" não for informado, o resultado retornado deverá ser um status http 400 e
      { "message": "\"name\" is required" }
  • [O campo "name" deve se do tipo string]

    • Se o campo "name" não for do tipo string, o resultado retornado deverá ser um status http 422 e
      { "message": "\"name\" must be a string" }
  • [O campo "name" é uma string com mais de 2 caracteres]

    • Se o campo "name" não for uma string com mais de 2 caracteres, o resultado retornado deverá ser um status http 422 e
      { "message": "\"name\" length must be at least 3 characters long" }

👉 Para amount

  • [O campo "amount" é obrigatório]

    • Se o campo "amount" não for informado, o resultado retornado deverá ser um status http 400 e
      { "message": "\"amount\" is required" }
  • [O campo "amount" deve ser do tipo string]

    • Se o campo "amount" não for do tipo string, o resultado retornado deverá ser um status http 422 e
      { "message": "\"amount\" must be a string" }
  • [O campo "amount" é uma string com mais de 2 caracteres]

    • Se o campo "amount" não for uma string com mais de 2 caracteres, o resultado retornado deverá ser um status http 422 e
      { "message": "\"amount\" length must be at least 3 characters long" }

👉 Para caso os dados sejam enviados corretamente

  • [Será cadastrado um produto com sucesso]
    • O resultado retornado para cadastrar o produto com sucesso é exibido conforme abaixo, com um status http 201:
      {
        "id": 1,
        "name": "Poção de cura",
        "amount": "20 gold",
      }

3 - Endpoint para o cadastro de pessoas usuárias

  • O endpoint é acessível através do caminho (/users);

  • As informações de pessoas usuárias cadastradas são salvas na tabela Users do banco de dados;

  • O endpoint deve receber a seguinte estrutura:

{
  "username": "string",
  "classe": "string",
  "level": 1,
  "password": "string"
}
Além disso, as seguintes verificações serão feitas:

👉 Para username

  • [O campo "username" é obrigatório]

    • Se a requisição não tiver o campo "username", o resultado retornado deverá ser um status http 400 e
      { "message": "\"username\" is required" }
  • [O campo "username" deve ser do tipo string]

    • Se o campo "username" não for do tipo string, o resultado retornado deverá ser um status http 422 e
      { "message": "\"username\" must be a string" }
  • [O campo "username" é uma string com mais de 2 caracteres]

    • Se o campo "username" não for do tipo string com mais de 2 caracteres, o resultado retornado deverá ser um status http 422 e
      { "message": "\"username\" length must be at least 3 characters long" }

👉 Para classe

  • [O campo "classe" é obrigatório]

    • Se a requisição não tiver o campo "classe", o resultado retornado deverá ser um status http 400 e
      { "message": "\"classe\" is required" }
  • [O campo "classe" deve ser do tipo string]

    • Se o campo "classe" não for do tipo string, o resultado retornado deverá ser um status http 422 e
      { "message": "\"classe\" must be a string" }
  • [O campo "classe" é uma string com mais de 2 caracteres]

    • Se o campo "classe" não for do tipo string com mais de 2 caracteres, o resultado retornado deverá ser um status http 422 e
      { "message": "\"classe\" length must be at least 3 characters long" }

👉 Para level

  • [O campo "level" é obrigatório]

    • Se a pessoa usuária não tiver o campo "level", o resultado retornado deverá ser um status http 400 e
      { "message": "\"level\" is required" }
  • [O campo "level" tem o tipo number]

    • Se o campo "level" não for do tipo number, o resultado retornado deverá ser um status http 422 e
      { "message": "\"level\" must be a number" }
  • [O campo "level" deve ser um número maior que 0]

    • Se o campo "level" não for do tipo number maior que 0, o resultado retornado deverá ser um status http 422 e
      { "message": "\"level\" must be greater than or equal to 1" }

👉 Para password

  • [O campo "password" é obrigatório]

    • Se a requisição não tiver o campo "password", o resultado retornado deverá ser um status http 400 e
      { "message": "\"password\" is required" }
  • [O campo "password" tem o tipo string]

    • Se o campo "password" não for do tipo string, o resultado retornado deverá ser um status http 422 e
      { "message": "\"password\" must be a string" }
  • [O campo "password" é uma string com 8 ou mais caracteres]

    • Se o campo "password" não for do tipo string com mais de 8 caracteres, o resultado retornado deverá ser um status http 422 e
      { "message": "\"password\" length must be at least 8 characters long" }

👉 Para caso os dados sejam enviados corretamente

  • [A pessoa usuária será cadastrada com sucesso]
    • Se a pessoa usuária for cadastrada com sucesso, o resultado deverá ser conforme o exibido abaixo, com um status http 201 e retornando um token:
    {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
    }

4 - Endpoint para listar todos os pedidos

  • O endpoint é acessível através do caminho (/orders).
  • Essa rota retorna todos os pedidos e os ids dos produtos associados a estes.
Além disso, as seguintes verificações serão feitas:

👉 Para orders

  • [Listar todos os pedidos com sucesso]
    • Quando houver mais de um pedido, o resultado retornado para listar pedidos com sucesso deverá ser conforme exibido abaixo, com um status http 200:
      [
        {
          "id": 1,
          "userId": 2,
          "productsIds": [1, 2]
        },
        {
          "id": 2,
          "userId": 2,
          "productsIds": [3, 4]
        }
      ]

5 - Endpoint para o login de pessoas usuárias

  • O endpoint é acessível através do caminho (/login).

  • A rota deve receber os campos username e password, e esses campos devem ser validados no banco de dados.

  • Um token JWT é gerado e retornado caso haja sucesso no login.

  • O endpoint deve receber a seguinte estrutura:

  {
    "username": "string",
    "password": "string"
  }
Além disso, as seguintes verificações serão feitas:

👉 Para caso haja problemas no login

  • [É validado que o campo "username" é enviado]

    • Se o login não tiver o campo "username", o resultado retornado deverá ser um status http 400 e
      { "message": "\"username\" is required" }
  • [É validado que o campo "password" é enviado]

    • Se o login não tiver o campo "password", o resultado retornado deverá ser um status http 400
      { "message": "\"password\" is required" }
  • [É validado que não é possível fazer login com um username inválido]

    • Se o login tiver o username inválido, o resultado retornado deverá ser um status http 401 e
      { "message": "Username or password invalid" }
  • [É validado que não é possível fazer login com uma senha inválida]

    • Se o login tiver a senha inválida, o resultado retornado deverá ser um status http 401 e
      { "message": "Username or password invalid" }

👉 Para caso os dados sejam enviados corretamente

  • [É possível fazer login com sucesso]
    • Se o login foi feito com sucesso, o resultado deverá ser um status http 200 e deverá retornar um token:
    {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
    }

6 - Endpoint para o cadastro de um pedido

  • O endpoint é acessível através do caminho (/orders);

  • Um pedido só pode ser criado caso a pessoa usuária esteja logada e o token JWT validado;

  • Os pedidos enviados são salvos na tabela Orders do banco de dados, salvando id da pessoa usuária da aplicação que fez esse pedido.

  • A tabela Products também é alterada, atualizando todos os produtos com os id incluídos na chave productsIds da requisição, e adicionando nesses produtos o orderId do pedido recém criado;

  • O endpoint deve receber a seguinte estrutura:

  {
    "productsIds": [1, 2]
  }
Além disso, as seguintes verificações serão feitas:

👉 Para token

  • [Não é possível cadastrar pedidos sem token]

    • Se o token não for informado, o resultado retornado deverá ser um status http 401 e
      { "message": "Token not found" }
  • [Não é possível cadastrar um pedido com token inválido]

    • Se o token informado não for válido, o resultado retornado deverá ser um status http 401 e
      { "message": "Invalid token" }

👉 Para products

  • [O campo "productsIds" é obrigatório]

    • Se o corpo da requisição não possuir o campo "productsIds", o resultado retornado deverá ser um status http 400 e
      { "message": "\"productsIds\" is required" }
  • [Não é possível criar um pedido com o campo "productsIds" não sendo um array]

    • Se o valor do campo "productsIds" não for um array, o resultado retornado deverá ser um status http 422 e
      { "message": "\"productsIds\" must be an array" }
  • [Não é possível cadastrar um pedido se o campo "productsIds" for um array vazio]

    • Se o campo "productsIds" possuir um array vazio, o resultado retornado deverá ser um status http 422 e
      { "message": "\"productsIds\" must include only numbers" }

👉 Para caso os dados sejam enviados corretamente

  • [Um pedido é criado com sucesso com 1 item]

    • O resultado retornado para cadastrar um pedido com sucesso deverá ser conforme exibido abaixo, com um status http 201:
      {
        "userId": 1,
        "productsIds": [1],
      }
  • [SUm pedido é criado com sucesso com vários itens]

    • O resultado retornado para cadastrar um pedido com sucesso deverá ser conforme exibido abaixo, com um status http 201:
      {
        "userId": 1,
        "productsIds": [1, 2]
      }

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published