Skip to content

IvanRafael-Dev/blogs-api-node

Repository files navigation

Boas vindas ao repositório do API de Blogs!

Habilidades

Nesse projeto, construi um back-end usando ORM com o pacote sequelize do npm, e fui capaz de:

  • Criar e associar tabelas usando models do sequelize
  • Construir endpoints para consumir os models que criar
  • Fazer um CRUD com o ORM

O que foi desenvolvido

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.


Desenvolvimento

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.

Executando o Projeto

  1. Faça o clone do repositório
- git clone git@github.com:IvanRafael-Dev/blogs-api-node.git
  1. Instale as dependências do projeto
- `npm install`
  1. 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
  1. Inicie a aplicação
- npm start

Execução de testes unitários

Utilize o Jest para executar os testes, use o comando a seguir para executar todos os testes:

npm test

Lista de Funcionalidades:

1 - Cadastro de usuários

  • 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:

Nome menor que 8 (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:

Email inválido (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:

Email inválido (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:

Email obrigatório (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:

Senha menor que 6 (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:

Senha Obrigatória (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:

Usuário Existente

2 - Login de usuários

  • 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:

Sem login (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:

Sem senha (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:

Email em branco (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:

Senha em branco (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:

Usuário não existe

3 - Listagem de usuários

  • 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:

Token Vazio

[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:

Token inválido

4 - Encontrar um usuário

  • 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:

Listar um usuário inexistente

[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:

Listar um usuário sem token

[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:

Listar um usuário com token inválido

5 - Adicionar categorias

  • 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: Criar categoria com sucesso

[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:

Cadastrar uma categoria com token inválido

[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:

Cadastrar uma categoria sem token

6 - Listar categorias existentes

  • 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:

Buscar uma categoria com token inválido

[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:

Buscar uma categoria sem token

7 - Adiciona um novo Post

  • 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:

blogpost sem content

[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:

blogpost sem content

[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:

blogpost sem categoryId

[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:

blogpost categoryId invalida

[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:

blogpost sem token

[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:

blogpost com token inválido

8 - Listagem dos Posts existentes

  • 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:

blogpost sem token

[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:

blogpost com token inválido

9 - Selecionar um post específico pelo ID

  • 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:

blogpost com token inválido

[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:

blogpost com token inválido

[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:

Listar um post inexistente

10 - Edição de post cadastrado

  • 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 e content.

  • 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.

editar com campo categorias

[Não é possível editar um blogpost com outro usuário]

Somente o usuário que criou o post poderá edita-lo.

blogpost com token inválido

[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:

blogpost com token inválido

[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:

blogpost com token inválido

[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:

blogpost com token inválido

[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:

blogpost com token inválido

11 - Remover post utilizando seu ID

  • 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:

blogpost com token inválido

[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:

blogpost com token inválido

[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:

blogpost com token inválido

[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:

blogpost com token inválido

12 - Remover usuário

  • 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:

Deletar com token inválido

[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:

Deletar sem token

13 - Busca de palavras em títulos ou conteúdos de posts

  • 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:

blogpost com token inválido

[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:

blogpost com token inválido

About

A CRUD API with NodeJs, ExpressJS, Sequelize and MySQL

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •