Skip to content

API com JavaScrip, MySQL(banco de dados), JWT(autenticação de usuário na rota), Joi(validação de dados) e Sequelize(ORM)

Notifications You must be signed in to change notification settings

Dogl4/Blogs-Api

Repository files navigation

Projeto Blogs API

Descrição

API para um blog. Desenvolvida em Node.js, com JavaScript, Express.js para ligar com rotas, Sequelize(ORM) para criar e gerenciar um banco de dados, MySQL, JWT para autenticação e Joi para validação de dados. Com sistema CRUD (POST, GET, PUT e DELETE) utilizando a arquitetura API-REST(Representational State Transfer).

📷 Screenshot
Screenshot da API
Figura 1.1 Gif da API
💻 Tecnologias utilizadas
  • JavaScript: Linguagem de programação.
  • NodeJS: Motor de JavaScript para criação de aplicações web.
  • ExpressJS: Framework para desenvolvimento da API.
  • MYSQL: Banco de dados.
  • Sequilize: ORM para o MYSQL.
  • Joi: Validação de dados.
  • JWT: Autenticação.
  • Dotenv: Carregamento de variáveis de ambiente.
  • Mocha: Framework de testes.
  • Chai: Framework de testes.
  • Sinon: Framework de testes.

Rodando API localmente

  1. Pré-requisitos

    Ter o NodeJS e o MySQL instalados.

  2. Baixando o repositório

    # clonando o repositório ou baixe por zip(ali em cima)
    $ git clone git@github.com:Dogl4/Blogs-Api.git
    
    # entrando na pasta do repositório
    $ cd Blogs-Api
    
    # instalando dependências
    $ npm install
  3. Definindo váriaveis de ambiente

    Renomei o arquivo .env.example para .env, substituindo os valores por seus respectivos dados locais.

  4. Criando o banco de dados

    # criando o banco de dados
    $ npm run init
    
    # populando o banco, executando as seeds
    $ npm run seed
    
    # se quiser deletar o banco de dados
    $ npm run drop
  5. Rodando a API

    # iniciando o servidor
    $ npm run start
    
    # iniciando o servidor em modo de desenvolvimento
    $ npm run dev
    # se não inicializar, verifica se não existe nada rodando na porta 3000, comando para linux
    $ lsof -i:3000
    
    # se existir, feche o processo, comando para linux
    $ kill -9 $(lsof -t -i:3000)
    🚪 Modificando a porta

    A porta padrão é 3000. Você pode alterar isso renomeando o arquivo .env.example para .env e modificando o valor da variável PORT.

Test

# unit test
$ npm run test

# test coverage
$ npm run test:cov
🛠 Imagem de cobertura de test
Screenshot da cobertura de test
Figura 2.1 Cobertura de testes (npm run test:cov)

Endpoints

Use algum dos seguintes programas para fazer as requisições: Postman ou Thunder Client ou Insomnia. Se estiver utilizando o Postman, vá em importe a collection.json do repositório, que está localizada em ./postman/collection.json. Rotas com 🔐 (protected) são protegidas por um token JWT.

Usuários

  • POST (cadastra)
    • Url:

      • /user
      • Exemplo: http://localhost:3000/user
    • Request:

      • Body:
          {
              "email": "doougllas@hotmail.com.br",
              "password": "123456"
          }
    • Response sucesso:

      • Status: 201 Created
      • Body:
        {
            "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiYWFhQGFhYS5jbyIsImlhdCI6MTY1OTM1NjE1NywiZXhwIjoxNjU5NDQyNTU3LCJzdWIiOiJhYWFAYWFhLmNvIn0.y3TmHszGD1XvS-PatCJ1zofM8ZLG4YnGm5UantcP2Ak"
        }
    • Response erro:

      • Status: 400 Bad Request

      • Body:

        {
            "message": "\"email\" is required"
        }
        {
            "message": "\"email\" is not allowed to be empty"
        }
        {
            "message": "\"password\" is required"
        }
        {
            "message": "\"password\" is not allowed to be empty"
        }
        {
            "message": "\"password\" length must be at least 6 characters long"
        }
      • Status: 409 Conflict

      • Body:

        {
            "message": "User already registered"
        }
  • POST (login)
    • Url:

      • /login
      • Exemplo: http://localhost:3000/login
    • Request:

      • Body:
          {
              "email": "doougllas@hotmail.com.br",
              "password": "123456"
          }
    • Response sucesso:

      • Status: 200 OK
      • Body:
        {
            "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiYWFhQGFhYS5jbyIsImlhdCI6MTY1OTUyNDkwNiwiZXhwIjoxNjU5NjExMzA2LCJzdWIiOiJhYWFAYWFhLmNvIn0.tHMoYbyjXGYEK0ZghfmUh3jmBOv4cZxRbDjZrYYKVL8"
        }
    • Response erro:

      • Status: 400 Bad Request
      • Body:
        {
            "message": "\"email\" is required"
        }
        {
            "message": "\"email\" is not allowed to be empty"
        }
        {
            "message": "\"email\" must be a valid email"
        }
        {
            "message": "\"password\" is required"
        }
        {
            "message": "\"password\" is not allowed to be empty"
        }
        {
            "message": "\"password\" length must be at least 6 characters long"
        }
        {
            "message": "Invalid fields"
        }
  • 🔐 GET (todos os usuários)
    • Url:

      • /user
      • Exemplo: http://localhost:3000/user
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
    • Response sucesso:

      • Status: 200 OK
      • Body:
        [
            {
                "id": 1,
                "displayName": "Lewis Hamilton",
                "email": "lewishamilton@gmail.com",
                "password": "123456",
                "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg"
            },
            {
                "id": 2,
                "displayName": "Michael Schumacher",
                "email": "MichaelSchumacher@gmail.com",
                "password": "123456",
                "image": "https://sportbuzz.uol.com.br/media/_versions/gettyimages-52491565_widelg.jpg"
            },
            {
                "id": 3,
                "displayName": null,
                "email": "aaa@aaa.co",
                "password": "123456",
                "image": null
            },
            {
                "id": 4,
                "displayName": null,
                "email": "doougllas@hotmail.com.br",
                "password": "123456",
                "image": null
            }
        ]
    • Response erro:

      • Status: 401 Unauthorized
      • Body:
        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
  • 🔐 GET (um usuário)
    • Url:

      • /user/:id
      • Exemplo: http://localhost:3000/user/1
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
    • Response sucesso:

      • Status: 200 OK
      • Body:
        {
            "id": 1,
            "displayName": "Lewis Hamilton",
            "email": "lewishamilton@gmail.com",
            "password": "123456",
            "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg"
        }
    • Response erro:

      • Status: 401 Unauthorized
      • Body:
        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
  • 🔐 DELETE (deleta usuário)
    • Url:

      • /user/me
      • Exemplo: http://localhost:3000/user/me
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
    • Response sucesso:

      • Status: 204 No Content
    • Response erro:

      • Status: 401 Unauthorized

      • Body:

        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
      • Status: 404 Not Found

      • Body:

        {
            "message": "User does not exist"
        }

Categorias

  • 🔐 POST (cadastra)
    • Url:

      • /categories
      • Exemplo: http://localhost:3000/categories
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
      • Body:
        {
            "name": "Programação"
        }
    • Response sucesso:

      • Status: 201 Created
      • Body:
        {
            "id": 4,
            "name": "Programação"
        }
    • Response erro:

      • Status: 400 Bad Request

      • Body:

        {
            "message": "\"name\" is required"
        }
        {
            "message": "\"name\" is not allowed to be empty"
        }
      • Status: 401 Unauthorized

      • Body:

        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
      • Status: 409 Conflict

      • Body:

        {
            "message": "Categorier already registered"
        }
  • 🔐 GET (todas categorias)
    • Url:

      • /categories
      • Exemplo: http://localhost:3000/categories
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
    • Response sucesso:

      • Status: 200 OK
      • Body:
        [
            {
                "id": 1,
                "name": "Inovação"
            },
            {
                "id": 2,
                "name": "Escola"
            },
            {
                "id": 3,
                "name": "1"
            },
            {
                "id": 4,
                "name": "Programação"
            }
        ]
    • Response erro:

      • Status: 401 Unauthorized
      • Body:
        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }

Posts

  • 🔐 POST (cadastra)
    • Url:

      • /post
      • Exemplo: http://localhost:3000/post
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
      • Body:
        {
            "title": "Post do Futuro",
            "content": "Inovação na escola",
            "categoryIds": [1,2]
        }
    • Response sucesso:

      • Status: 201 Created
      • Body:
        {
            "id": 10,
            "userId": 7,
            "title": "Post do Futuro",
            "content": "Inovação na escola"
        }
    • Response erro:

      • Status: 400 Bad Request

      • Body:

        {
            "message": "\"title\" is required"
        }
        {
            "message": "\"title\" is not allowed to be empty"
        }
        {
            "message": "\"content\" is required"
        }
        {
            "message": "\"content\" is not allowed to be empty"
        }
        {
            "message": "\"categoryIds\" is required"
        }
        {
            "message": "\"categoryIds\" must be an array"
        }
        {
            "message": "\"categoryIds\" does not contain 1 required value(s)"
        }
        {
            "message": "\"categoryIds[0]\" must be a number"
        }
      • Status: 401 Unauthorized

      • Body:

        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
      • Status: 404 Not Found

      • Body:

        {
            "message": "\"categoryIds\" not found"
        }
  • 🔐 GET (todos posts)
    • Url:

      • /post
      • Exemplo: http://localhost:3000/post
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
    • Response sucesso:

      • Status: 200 OK
      • Body:
        [
            {
                "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"
                    }
                ]
            },
            {
                "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"
                    }
                ]
            }
        ]
    • Response erro:

      • Status: 401 Unauthorized
      • Body:
        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
  • 🔐 GET (um post)
    • Url:

      • /post/:id
      • Exemplo: http://localhost:3000/post/1
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
    • Response sucesso:

      • Status: 200 OK
      • Body:
        {
            "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"
                }
            ]
        }
    • Response erro:

      • Status: 401 Unauthorized
      • Body:
        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
  • 🔐 GET (um post por título)
    • Url:

      • /post/search?q=
      • Exemplo: http://localhost:3000/post/search?q=vamos
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
    • Response sucesso:

      • Status: 200 OK
      • Body:
        [
            {
                "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"
                    }
                ]
            }
        ]
    • Response erro:

      • Status: 401 Unauthorized
      • Body:
        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
  • 🔐 PUT (edit um post)
    • Url:

      • /post/:id
      • Exemplo: http://localhost:3000/post/1
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
      • Body:
        {
            "title": "Refletir sobre o vôo",
            "content": "Foguete tem ré"
        }
    • Response sucesso:

      • Status: 200 OK
      • Body:
        {
            "0": {
                "id": 1,
                "name": "Inovação"
            },
            "1": {
                "id": 2,
                "name": "Escola"
            },
            "title": "Refletir sobre o vôo",
            "content": "Foguete tem ré",
            "userId": 3
        }
    • Response erro:

      • Status: 400 Bad Request

      • Body:

        {
            "message": "\"title\" is required"
        }
        {
            "message": "\"title\" is not allowed to be empty"
        }
        {
            "message": "\"content\" is required"
        }
        {
            "message": "\"content\" is not allowed to be empty"
        }
      • Status: 401 Unauthorized

      • Body:

        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
        {
            "message": "You can only edit your own posts"
        }
      • Status: 404 Not Found

      • Body:

        {
            "message": "Post does not exist"
        }
  • 🔐 DELETE (deleta usuário)
    • Url:

      • /post/:id
      • Exemplo: http://localhost:3000/post/1
    • Request:

      • Headers:
          {
              "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc0FkbWluIjpmYWxzZSwidXNlckVtYWlsIjoiZG9vdWdsbGFzQGhvdG1haWwuY29tLmJyIiwiaWF0IjoxNjU5NTI1NjgzLCJleHAiOjE2NTk2MTIwODMsInN1YiI6ImRvb3VnbGxhc0Bob3RtYWlsLmNvbS5iciJ9.HlIe_JlHWPBdqyh80fCR-umYbVwy0aFqaGIMI63kgWQ",
          }
    • Response sucesso:

      • Status: 204 No Content
    • Response erro:

      • Status: 401 Unauthorized

      • Body:

        {
            "message": "Token not found"
        }
        {
            "message": "Expired or invalid token"
        }
        {
            "message": "Unauthorized user"
        }
      • Status: 404 Not Found

      • Body:

        {
            "message": "Post does not exist"
        }

Colaboradores

Estas pessoas participaram deste projeto:

Foto do Pedro Barreto no GitHub
Pedro Barreto
Foto Trybe
Trybe
Desenvolvimento do código da api, requisições, validações. Ideia e banco.

About

API com JavaScrip, MySQL(banco de dados), JWT(autenticação de usuário na rota), Joi(validação de dados) e Sequelize(ORM)

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published