BlogsAPI é um projeto back-end, onde foi desenvolvido uma API RESTFul para um blog, utilizando arquitetura MSC - Models, Services e Controller utilizando MySQL como banco de dados.
A base do projeto foi desenvolvido pela Trybe (Dockerfile, package.json, docker-compose.yml e outras configurações). Arquivos desenvolvidos por mim:
- tudo na pasta
./src/;
Tecnologias aplicadas por mim no projeto:
- NodeJS;
- Express;
- Sequelize;
- MySQL;
- Docker;
- JWT;
Etapas de instalação:
- Certifique-se de ter o docker instalado com as versões 1.29 ou superior;
- Clone o repositório;
- Acesse a pasta raiz do repositório e execute o comando
docker-compose up -d; - O comando acima irá subir dois containers: um container Node chamado blogs_api, e um container MySQL de nome blogs_api_db;
- Você deve acessar o container Node (blogs_api) para instalar as dependências do projeto. Execute o comando:
docker exec -it blogs_api bash; - Já dentro da linha de comando do 'blogs_api', instale as dependências do projeto com o comando
npm install; - Execute o comando
npm run prestart. Esse comando irá rodar os comandos Sequelize para criar e migrar o banco de dados MySQL; - Execute a aplicação com
npm start; - Você pode testar e depurar a API com programas como ThunderClient ou Postman. As rotas e os retornos esperados são explicados em 'Requisitos do projeto'.;
- A porta padrão para testar os requisitos é a 3000. (http://localhost:3000/);
Para orientar a construção das tabelas através do ORM, foi utilizado o DER abaixo:

Foi criado migrations para as tabelas na pasta './src/migrations/'.
O corpo da requisição deverá seguir o formato abaixo:
{
"email": "lewishamilton@gmail.com",
"password": "123456"
}Caso a requisição não tiver todos os campos devidamente preenchidos, o retorno será um status 400com a mensagem:
{
"message": "Some required fields are missing"
}Caso a requisição receba um usuário errado/inexistente, o retorno será um status 400com a mensagem:
{
"message": "Invalid fields"
}Se o login for feito com sucesso, o retorno será status 200com um token de autenticação:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjp7ImlkIjo1LCJkaXNwbGF5TmFtZSI6InVzdWFyaW8gZGUgdGVzdGUiLCJlbWFpbCI6InRlc3RlQGVtYWlsLmNvbSIsImltYWdlIjoibnVsbCJ9LCJpYXQiOjE2MjAyNDQxODcsImV4cCI6MTYyMDY3NjE4N30.Roc4byj6mYakYqd9LTCozU1hd9k_Vw5IWKGL4hcCVG8"
}O corpo da requisição deverá seguir o formato abaixo:
{
"displayName": "Brett Wiltshire",
"email": "brett@email.com",
"password": "123456",
"image": "http://4.bp.blogspot.com/_YA50adQ-7vQ/S1gfR_6ufpI/AAAAAAAAAAk/1ErJGgRWZDg/S45/brett.png"
// a imagem não é obrigatória
}Caso displayName, email ou password não estejam preenchido, o sistema retornará status 400 com uma mensagem personalizada, dependendo do campo que esteja faltando:
{
"message": "\"displayName\" length must be at least 8 characters long"
}{
"message": "\"email\" must be a valid email"
}{
"message": "\"password\" length must be at least 6 characters long"
}Também é feito uma conferência para não ser possível cadastrar um email que já esteja cadastrado. Caso o email já esteja cadastrado, será retornado status 409com a mensagem:
{
"message": "User already registered"
}Caso tudo esteja correto e o usuário seja cadastrado corretamente, o retorno será status 201com o token:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjp7ImlkIjo1LCJkaXNwbGF5TmFtZSI6InVzdWFyaW8gZGUgdGVzdGUiLCJlbWFpbCI6InRlc3RlQGVtYWlsLmNvbSIsImltYWdlIjoibnVsbCJ9LCJpYXQiOjE2MjAyNDQxODcsImV4cCI6MTYyMDY3NjE4N30.Roc4byj6mYakYqd9LTCozU1hd9k_Vw5IWKGL4hcCVG8"
}Os próximos requisitos precisarão do token para serem testados. O token gerado ou pelo login, ou pelo cadastro do usuário deve ser salvo como header no formato:
header: authorization
value: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZGlzcGxheU5hbWUiOiJGZWxpcGUgQ3J1eiIsImVtYWlsIjoiZmVsaXBlQGVtYWlsLmNvbSIsInBhc3N3b3JkIjoiMTIzNDU2IiwiaW1hZ2UiOiJodHRwOi8vNC5icC5ibG9nc3BvdC5jb20vX1lBNTBhZFEtN3ZRL1MxZ2ZSXzZ1ZnBJL0FBQUFBQUFBQUFrLzFFckpHZ1JXWkRnL1M0NS9icmV0dC5wbmciLCJpYXQiOjE2OTE0MTMzOTcsImV4cCI6MTY5MzE0MTM5N30.hELaGIdRMPw9xruZhH5Rr8epEkkiqq1muYTXEzGY9VU
(sem aspas)Caso o token seja inexistente o retorno será status 401com a mensagem:
{
"message": "Token not found"
}Se o token for inválido ou estiver expirado, o retorno será status 401e a mensagem:
{
"message": "Expired or invalid token"
}Ao listar os usuário com sucesso, o retorno será status 200com a mensagem:
[
{
"id": 1,
"displayName": "Lewis Hamilton",
"email": "lewishamilton@gmail.com",
"image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg"
},
/* ... */
]Ao listar um usuário com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http 200:
{
"id": 1,
"displayName": "Lewis Hamilton",
"email": "lewishamilton@gmail.com",
"image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg"
}Caso o id do usuário solicitado seja inexistente, o retorno será status 404:
{
"message": "User does not exist"
}O corpo da requisição deverá seguir o formato abaixo:
{
"name": "Typescript"
}caso "name" não for preenchido, o retorno será status 400 com a mensagem:
{
"message": "\"name\" is required"
}Se a categoria for criada com sucesso, o retorno será status 201:
{
"id": 3,
"name": "Typescript"
}Ao listar as categorias com sucesso, status 200:
[
{
"id": 1,
"name": "Inovação"
},
{
"id": 2,
"name": "Escola"
},
/* ... */
]11 - Crie o modelo PostCategory em src/models/PostCategory.js com as propriedades e associações corretas
O corpo da requisição deverá seguir o formato abaixo:
{
"title": "Latest updates, August 1st",
"content": "The whole text for the blog post goes here in this key",
"categoryIds": [1, 2]
}Ao listar posts com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http 200:
[
{
"id": 1,
"title": "Post do Ano",
"content": "Melhor post do ano",
"userId": 1,
"published": "2011-08-01T19:58:00.000Z",
"updated": "2011-08-01T19:58:51.000Z",
"user": {
"id": 1,
"displayName": "Lewis Hamilton",
"email": "lewishamilton@gmail.com",
"image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg"
},
"categories": [
{
"id": 1,
"name": "Inovação"
}
]
},
/* ... */
]o listar um post com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http 200:
{
"id": 1,
"title": "Post do Ano",
"content": "Melhor post do ano",
"userId": 1,
"published": "2011-08-01T19:58:00.000Z",
"updated": "2011-08-01T19:58:51.000Z",
"user": {
"id": 1,
"displayName": "Lewis Hamilton",
"email": "lewishamilton@gmail.com",
"image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg"
},
"categories": [
{
"id": 1,
"name": "Inovação"
}
]
}Caso o post não exista, o retorno será status 404 com a mensagem:
{
"message": "Post does not exist"
}O corpo da requisição deverá seguir o formato abaixo:
{
"title": "Latest updates, August 1st",
"content": "The whole text for the blog post goes here in this key"
}