Este projeto consolida o aprendizado da ferramenta TypeScript por meio da construção de uma API Node Express utilizando variáveis e funções com tipagens TypeScript. O projeto foi desenvolvido utilizando as ferramentas TypeScript, Node, Sequelize e JWT (JSON Web Token) para a criação de uma loja de itens medievais, no formato de uma API RESTful com banco de dados.
Algumas camadas do modelo MSC (Model, Service e Controller) foram desenvolvidas utilizando o JWT para autenticação de rotas. Além disso, foram desenvolvidos testes para garantir o correto funcionamento da aplicação.
- TypeScript
- Node
- Sequelize
- Construção de uma API CRUD e banco de dados
- Sistema de autenticação utilizando JWT (JSON Web Token)
- Testes unitários e de integração com: Mocha, Chai e Sinon
- TypeScript
- Node
- Sequelize
- JWT (JSON Web Token)
- Mocha.js
- Chai.js
- Sinon.js
⚠️ É necessário ter o Docker instalado para executar este projeto
Passo a passo
- Clone o repositório em uma pasta de preferência
git clone git@github.com:allysonbogo/project-trybesmith.git
- Entre na pasta raíz do projeto e instale todas as dependências
npm install
- Para rodar o projeto é necessário executar o comando abaixo no diretório raiz do projeto. Isso fará com que os containers docker sejam orquestrados e a aplicação esteja disponível
docker-compose up -d
- As dependências do projeto serão instaladas juntamente com o início do container. Após isso, no mesmo terminal em que o container foi orquestrado, digite os comandos abaixo para acessar o bash do container e iniciar o servidor
docker exec -it trybesmith_api bash
npm start
- Para iniciar o servidor com live-reload, ao invés de
npm start
digite o comando abaixo
npm run dev
-
Para visualização da interface da API podem ser utilizados o Thunder Client, Postman, Insomnia ou alguma outra ferramenta de sua preferência
-
Para testar o projeto use o seguinte script no terminal em que o container foi orquestrado
npm run test:mocha
Rotas
Método | Funcionalidade | URL |
---|---|---|
POST |
Realiza o login de uma pessoa usuária cadastrada | http://localhost:3001/login |
A estrutura do body da requisição deverá seguir o padrão abaixo:
{
"username": "string",
"password": "string"
}
A resposta da requisição é a seguinte com status 201
:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjp7ImlkIjo1LCJkaXNwbGF5TmFtZSI6InVzdWFyaW8gZGUgdGVzdGUiLCJlbWFpbCI6InRlc3RlQGVtYWlsLmNvbSIsImltYWdlIjoibnVsbCJ9LCJpYXQiOjE2MjAyNDQxODcsImV4cCI6MTYyMDY3NjE4N30.Roc4byj6mYakYqd9LTCozU1hd9k_Vw5IWKGL4hcCVG8"
}
⚠️ O token acima é fictício, o token verdadeiro é gerado a partir da ferramenta JWT (JSON Web Token), utilizando uma palavra-passe e um payload secretos
A requisição irá falhar nos seguintes casos:
- A rota retorna um erro400
{ "message": "\"username\" and \"password\" are required" }
, caso a requisição não receba o campo username
; - A rota retorna um erro
400
{ "message": "\"username\" and \"password\" are required" }
, caso a requisição não receba o campo password
com formato válido; - A rota retorna um erro
401
{ "message": "Username or password invalid" }
, caso a requisição receba um username
que não exista no banco de dados; - A rota retorna um erro
401
{ "message": "Username or password invalid" }
, caso a requisição receba um password
que não corresponda à senha salva no banco de dados; Autenticação
⚠️ Após o login de uma pessoa usuária cadastrada, é gerado umtoken
aleatório, o qual será autenticado na rota de cadastro de um novo pedido
A requisição irá falhar nos seguintes casos:
- É disparado o erro401
{ "message": "Token not found" }
, ao fazer uma operação sem um token; - É disparado o erro
401
{ "message": "Invalid token" }
, ao fazer uma operação com um token expirado ou inválido; Rotas
Método | Funcionalidade | URL |
---|---|---|
POST |
Realiza o cadastro de um produto | http://localhost:3001/products |
A estrutura do body da requisição deverá seguir o padrão abaixo:
{
"name": "Martelo de Thor",
"price": "30 peças de ouro",
"orderId": 1
}
⚠️ Como os produtos são únicos e exclusivos, novos produtos devem receber um orderId ao serem criados, vinculando o produto à uma pessoa específica
A resposta da requisição é a seguinte com status 201
:
{
"id": 1
"name": "Martelo de Thor",
"price": "30 peças de ouro",
"orderId": 1
}
A requisição irá falhar nos seguintes casos:
- A rota retorna um erro400
{ "message": "\"name\" is required" }
, caso a requisição não receba o campo name
; - A rota retorna um erro
422
{ "message": "\"name\" must be a string" }
, caso o campo name
não seja do tipo string; - A rota retorna um erro
422
{ "message": "\"name\" length must be at least 3 characters long" }
, caso o campo name
não tenha pelo menos 3 caracteres; - A rota retorna um erro
400
{ "message": "\"price\" is required" }
, caso a requisição não receba o campo price
; - A rota retorna um erro
422
{ "message": "\"price\" must be a string" }
, caso o campo price
não seja do tipo string; - A rota retorna um erro
422
{ "message": "\"price\" length must be at least 3 characters long" }
, caso o campo price
não tenha pelo menos 3 caracteres; 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": "Pedra Filosofal",
"price": "20 gold",
"orderId": null
},
{
"id": 2,
"name": "Lança do Destino",
"price": "100 diamond",
"orderId": 1
},
...
]
Rotas
Método | Funcionalidade | URL |
---|---|---|
GET |
Retorna uma lista de pedidos | http://localhost:3001/orders |
A resposta da requisição é a seguinte com status 200
:
[
{
"id": 1,
"userId": 2,
"productIds": [1, 2]
},
{
"id": 2,
"userId": 1,
"productIds": [3, 4]
}
...
]
Método | Funcionalidade | URL |
---|---|---|
POST |
Realiza o cadastro de um pedido | http://localhost:3001/orders |
A estrutura do body da requisição deverá seguir o padrão abaixo:
{
"userId": 1
"productIds": [1, 2],
}
Para o cadastro de um pedido é necessário enviar um token de autenticação, o qual é gerado ao realizar o login. A resposta da requisição é a seguinte com status 201
:
{
"userId": 1,
"productIds": [1, 2]
}
A requisição irá falhar nos seguintes casos:
- A rota retorna um erro400
{ "message": "\"userId\" is required" }
, caso a requisição não receba o campo userId
; - A rota retorna um erro
422
{ "message": "\"userId\" must be a number" }
, caso o campo userId
não seja do tipo number; - A rota retorna um erro
404
{ "message": "\"userId\" not found" }
, caso o userId
não esteja cadastrado no banco de dados; - A rota retorna um erro
400
{ "message": "\"productIds\" is required" }
, caso a requisição não receba o campo productIds
; - A rota retorna um erro
422
{ "message": "\"productIds\" must be an array" }
, caso o campo productIds
não seja do tipo array; - A rota retorna um erro
422
{ "message": "\"productIds\" must include only numbers" }
, caso o campo productIds
esteja vazio ou inclua itens que não sejam do tipo número;