Nesse projeto, construi um back-end usando ORM
com o pacote sequelize
do npm
, e fui capaz de:
- Criar e associar tabelas usando
models
dosequelize
- Construir endpoints para consumir os models que criar
- Fazer um
CRUD
com oORM
Foi arquiteturado, uma API de um CRUD posts de blog (com o sequelize). Começando pela API, desenvolvi alguns endpoints (seguindo os princípios do REST) que foram conectados ao banco de dados.
Foi criada uma tabela para os usuários que desejam se cadastrar na aplicação e também uma tabela de Categorias para seus Posts. Por fim a tabela de Posts foi o maior foco, guardando todas as informações dos posts realizados na plataforma.
Foi desenvolvida uma aplicação em Node.js
usando o pacote sequelize
para fazer um CRUD
de posts.
Para fazer um post é necessário usuário e login, portanto foi trabalhada a relação entre user
e post
. Também foi necessário a utilização de categorias para os posts, assim trabalhando a relação de posts
para categorias
e de categorias
para posts
.
- Faça o clone do repositório
- git clone git@github.com:IvanRafael-Dev/blogs-api-node.git
- Instale as dependências do projeto
- `npm install`
- O projeto utiliza o MySQL como banco de dados. Certifique-se de estar com o serviço do MySQL rodando em sua máquina
- sudo systemctl start mysql.service
- Inicie a aplicação
- npm start
Utilize o Jest para executar os testes, use o comando a seguir para executar todos os testes:
npm test
-
POST
/users
-
Adiciona um novo user a sua tabela no banco de dados;
-
O corpo da requisição deverá ter o seguinte formato:
{ "displayName": "Brett Wiltshire", "email": "brett@email.com", "password": "123456", "image": "http://4.bp.blogspot.com/_YA50adQ-7vQ/S1gfR_6ufpI/AAAAAAAAAAk/1ErJGgRWZDg/S45/brett.png" }
-
O campo
displayName
deverá ser uma string com no mínimo de 8 caracteres; -
O campo
email
será considerado válido se tiver o formato<prefixo>@<domínio>
e se for único. Ele é obrigatório. -
A senha deverá conter 6 caracteres. Ela é obrigatória.
-
Caso exista uma pessoa com o mesmo email na base, é retornado o seguinte erro:
{ "message": "User already registered" }
[Não é possível cadastrar usuário com o campo displayName
menor que 8 caracteres]
Se o usuário tiver o campo "displayName" menor que 8 caracteres o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[Não é possível cadastrar usuário com o campo email
com formato email: rubinho
]
Se o usuário tiver o campo "email" com o formato email: rubinho
o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[Não é possível cadastrar usuário com o campo email
com formato email: @gmail.com
]
Se o usuário tiver o campo "email" com o formato email: @gmail.com
o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[O campo email
é obrigatório]
Se o usuário não tiver campo "email" o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[Não é possível cadastrar usuário com o campo password
diferente de 6 caracteres]
Se o usuário tiver o campo "password" menor ou maior que 6 caracteres o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[O campo password
é obrigatório]
Se o usuário não tiver campo "password" o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[Não é possível cadastrar um usuário com email já existente]
Se o usuário cadastrar o campo "email" com um email que já existe, o resultado retornado deverá ser conforme exibido abaixo, com um status http 409
:
-
POST
/login
-
O corpo da requisição deverá seguir o formato abaixo:
{ "email": "email@mail.com", "password": "123456" }
[Não é possível fazer login sem o campo email
]
Se o login não tiver o campo "email" o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[Não é possível fazer login sem o campo password
]
Se o login não tiver o campo "password" o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[Não é possível fazer login com o campo email
em branco]
Se o login tiver o campo "email" em branco o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
Não é possível fazer login com o campo password
em branco]
Se o login tiver o campo "password" em branco o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
(As contrabarras
\
estão escapando as aspas de dentro da string)
[Não é possível fazer login com um usuário que não existe]
Se o login for com usuário inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
-
GET
/user
-
Lista todos os Users e os retorna na seguinte estrutura:
[ { "id": "401465483996", "displayName": "Brett Wiltshire", "email": "brett@email.com", "image": "http://4.bp.blogspot.com/_YA50adQ-7vQ/S1gfR_6ufpI/AAAAAAAAAAk/1ErJGgRWZDg/S45/brett.png" } ]
[Não é possível listar usuários sem o token na requisição]
Se o token for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível listar usuários com o token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
-
GET
/user/:id
-
Retorna os detalhes do usuário baseado no
id
da rota. Os dados têm o seguinte formato:{ "id": "401465483996", "displayName": "Brett Wiltshire", "email": "brett@email.com", "image": "http://4.bp.blogspot.com/_YA50adQ-7vQ/S1gfR_6ufpI/AAAAAAAAAAk/1ErJGgRWZDg/S45/brett.png" }
[Não é possível listar um usuário inexistente]
Se o usuário for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http 404
:
[Não é possível listar um determinado usuário sem o token na requisição]
Se o token for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível listar um determinado usuário com o token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
-
POST
/categories
-
O corpo da requisição deve ter a seguinte estrutura:
{
"name": "Inovação"
}
[Não é possível cadastrar uma categoria sem o campo name]
Se ao tentar cadastrar uma categoria sem o campo name o resultado retornado deverá ser conformo exibido abaixo, com um status http 400:
[Não é possível cadastrar uma determinada categoria com o token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível cadastrar uma determinada categoria sem o token na requisição]
Se o token for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
-
GET
/categories
-
Esse endpoint lista todas as Categorias e as retorna na seguinte estrutura:
[
{
"id": 1,
"name": "Escola"
},
{
"id": 2,
"name": "Inovação"
}
]
[Não é possível listar as categorias com o token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível cadastrar uma determinada categoria sem o token na requisição]
Se o token for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
-
POST
/post
-
O corpo da requisição deve ter a seguinte estrutura:
{ "title": "Latest updates, August 1st", "content": "The whole text for the blog post goes here in this key", "categoryIds": [1, 2] }
[Não é possível cadastrar um blogpost sem o campo title
]
Se não conter o campo title
o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
[Não é possível cadastrar um blogpost sem o campo content
]
Se não conter o campo content
o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
[Não é possível cadastrar um blogpost sem o campo categoryIds
]
Se não conter o campo categoryIds
o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
[Não é possível cadastrar um blogpost com uma categoryIds
inexistente]
Se o campo categoryIds
tiver uma categoria inexistente, o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
[Não é possível cadastrar um blogpost sem o token]
Se não conter o token o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível cadastrar um blogpost com o token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
-
GET
/post
-
Retorna a seguinte estrutura:
[
{
"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_2017_Malaysia.jpg"
},
"categories": [
{
"id": 1,
"name": "Inovação"
}
]
}
]
[Não é possível listar blogpost sem token]
Se não conter o token o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível listar blogpost com token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
- GET
post/:id
- Retorna um BlogPost com o
id
especificado. O retorno têm o seguinte formato:
{
"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"
}
]
}
[Não é possível listar um blogpost sem token]
Se não conter o token o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível listar um blogpost com token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível listar um blogpost inexistente]
Se o id do post for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 404
:
-
PUT
/post/:id
-
O endpoint deve receber um BlogPost que irá sobrescrever o original com o
id
especificado na URL. Só é permitido para o usuário que criou o BlogPost. -
A(s) categoria(s) do post não podem ser editadas, somente o
title
econtent
. -
O corpo da requisição deve ter a seguinte estrutura:
{ "title": "Latest updates, August 1st", "content": "The whole text for the blog post goes here in this key" }
[Não é possível editar as categorias de um blogpost]
Só será possível editar o título ou o conteúdo de um post.
[Não é possível editar um blogpost com outro usuário]
Somente o usuário que criou o post poderá edita-lo.
[Não possível editar um blogpost sem token]
Se não conter o token o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não possível editar um blogpost com token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não possível editar um blogpost sem o campo title
]
Se não conter o campo title
o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
[Não possível editar um blogpost sem o campo content
]
Se não conter o campo content
o resultado retornado deverá ser conforme exibido abaixo, com um status http 400
:
-
DELETE
post/:id
-
Deleta o post com o
id
especificado. Só é permitido para o usuário que criou o BlogPost.
[Não é possível deletar um blogpost com outro usuário]
Se não for o dono do blogpost o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível deletar um blogpost inexistente]
Se o blogpost nao existir o resultado retornado deverá ser conforme exibido abaixo, com um status http 404
:
[Não é possível deletar um blogpost sem o token]
Se não contém o token o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível deletar um blogpost com o token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
-
DELETE
/user/me
-
Utilizando o token de autenticação nos headers, o usuário correspondente pode ser apagado.
Ao deletar um usuário com sucesso é retornado um status http 204
:
Não é possivel excluir meu usuário com token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possivel excluir meu usuário sem o token]
Se não conter o token o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
-
GET
post/search?q=:searchTerm
-
Retorna uma array de BlogPosts que contenham em seu título, ou conteúdo, o termo pesquisado no
queryParam
da URL. O retorno têm o seguinte formato:
[
{
"id": 2,
"title": "Vamos que vamos",
"content": "Foguete não tem ré",
"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": 2,
"name": "Escola"
}
]
}
]
- Caso nenhum BlogPost satisfaça a busca, é retornado um array vazio.
[Não é possível buscar um blogpost sem o token]
Se não contém o token o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
:
[Não é possível buscar um blogpost com o token inválido]
Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http 401
: