Foi desenvolvido um projeto de loja online de itens medievais, utilizando Typescript, no formato de uma API. A aplicação foi construída com as camadas de Models, Service e Controllers e permite realizar operações básicas em um banco de dados, como criar, ler, atualizar e excluir registros (CRUD). Foram criados alguns pontos de acesso (endpoints) que interagem com um banco de dados MySQL, permitindo ler e gravar informações.
🐳 Rodando no Docker
Rode os serviços
node
edb
com o comandodocker-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 chamadotrybesmith_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 [Caso existam] 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.
⚠ Atenção ⚠ O git dentro do container não vem configurado com suas credenciais. Faça os commits fora do container, ou configure as suas credenciais do git dentro do container.
⚠ Atenção ⚠ Não rode o comando npm audit fix! Ele atualiza várias dependências do projeto, e essa atualização gera conflitos com o avaliador.
✨ Dica: A extensão Remote - Containers
(que estará na seção de extensões recomendadas do VS Code) é indicada para que você possa desenvolver sua aplicação no container Docker direto no VS Code, como você faz com seus arquivos locais.
🏦 Conexão com o Banco
A conexão do banco local deverá conter os seguintes parâmetros:
import dotenv from 'dotenv';
import mysql from 'mysql2/promise';
dotenv.config();
const connection = mysql.createPool({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
}); // sua conexão NÃO deve ter o database, este deve ser especificado em cada query
export default connection;
host: process.env.MYSQL_HOST
user: process.env.MYSQL_USER
password: process.env.MYSQL_PASSWORD
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 IF NOT EXISTS Trybesmith;
CREATE TABLE Trybesmith.users (
id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL,
username TEXT NOT NULL,
vocation TEXT NOT NULL,
level INTEGER NOT NULL,
password TEXT NOT NULL
);
CREATE TABLE Trybesmith.orders (
id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL,
user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES Trybesmith.users (id)
);
CREATE TABLE Trybesmith.products (
id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
amount TEXT NOT NULL,
order_id INTEGER,
FOREIGN KEY (order_id) REFERENCES Trybesmith.orders (id)
);
O arquivo Trybesmith.sql
contém as queries que criam e populam o banco como o teste faz, e os testes restauram o banco de dados após sua execução.
Para que o avaliador funcione corretamente, tanto local quanto remoto, sua connection.ts
não deve conter o database e suas queries devem conter o banco de dados explicitamente como o exemplo abaixo:
SELECT * FROM Trybesmith.products;
🍪 Informações sobre a API
-
O projeto deve rodar na porta 3001;
-
O arquivo
index.ts
existe para rodar corretamente os testes. Toda a chamada de rotas do projeto deverá ser feita dentro do arquivoapp.ts
;
-
Use os verbos
HTTP
adequados para cada operação; -
Agrupe e padronize suas URL em cada recurso;
-
Garanta que seus endpoints sempre retornem uma resposta, havendo sucesso nas operações ou não;
-
Retorne os códigos de status corretos (recurso criado, erro de validação, etc).
Há dois arquivos no diretório ./src/
: index.ts
e app.ts
, ambos não devem ser renomeados ou apagados.
Você poderá fazer modificações em ambos os arquivos, porém no arquivo app.ts
o seguinte trecho de código não deve ser removido:
import express from 'express';
const app = express();
app.use(express.json());
export default app;
Isso está configurado para o avaliador funcionar corretamente.
-
O endpoint deve ser acessível através do caminho (
/products
); -
Os produtos enviados devem ser salvos na tabela
products
do banco de dados; -
O endpoint deve receber a seguinte estrutura:
{
"name": "Espada longa",
"amount": "30 peças de ouro"
}
- O endpoint deve ser acessível através do caminho (
/products
);
-
O endpoint deve ser acessível através do caminho (
/users
); -
As informações de pessoas usuárias cadastradas devem ser salvas na tabela
users
do banco de dados; -
O endpoint deve receber a seguinte estrutura:
{
"username": "MAX",
"vocation": "swordsman",
"level": 10,
"password": "SavingPeople"
}
- O endpoint deve ser acessível através do caminho (
/orders
). - Essa rota deve retornar todos os pedidos e os
id
s dos produtos associados a estes.
-
O endpoint deve ser acessível através do caminho (
/login
). -
A rota deve receber os campos
username
epassword
, e esses campos devem ser validados no banco de dados. -
Um token
JWT
deve ser gerado e retornado caso haja sucesso no login. No seu payload deve estar presente o id e username. -
O endpoint deve receber a seguinte estrutura:
{
"username": "string",
"password": "string"
}
-
Vamos realizar as validações referentes a criação do endpont do requisito 1?
-
Neste requisito de validação, não é necessário conectar com o banco de dados
- Neste requisito de validação, não é necessário conectar com o banco de dados
-
O endpoint deve ser 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 devem ser salvos na tabela
orders
do banco de dados, salvandoid
da pessoa usuária da aplicação que fez esse pedido. -
A tabela
products
também deve ser alterada, atualizando todos os produtos com osid
incluídos na chaveproductsIds
da requisição, e adicionando nesses produtos oorderId
do pedido recém criado; -
O endpoint deve receber a seguinte estrutura:
{
"productsIds": [1, 2]
}