Servidor para Blog, com Autenticação JWT - Node.Js & Mysql
Vitor Alecrim
Posted on December 1, 2023
Apresentação
Olá, como vai? Eu sou o Vitor e estou de volta com um novo projeto. Já se passou algum tempo desde o meu último tutorial, pois estive ocupado com outras atividades nos últimos meses. No entanto, é hora de retornarmos ao fascinante mundo do código.
Hoje, vamos criar um servidor em Node.js para uma página de blog. Nosso servidor terá a capacidade de registrar usuários e autenticá-los usando JWT. Além disso, abordaremos temas como registro, consultas, edição e remoção de dados, como texto e imagens, do banco de dados MySQL.
Com a sua API pronta, você poderá alimentar a sua aplicação frontend. Caso ainda não tenha um site, siga para o tutorial de frontend*.
Ao longo deste tutorial, vou me esforçar para ser o mais sucinto e claro possível.
Antes de prosseguirmos com nossa aplicação, é necessário criar o banco de dados. Utilizaremos o banco de dados MySQL para desenvolver nosso projeto. Você pode optar pela plataforma de gerenciamento de banco de dados com a qual estiver mais familiarizado, como DBeaver, entre outras.
No meu caso, vou utilizar o terminal:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 8.0.35-0ubuntu0.22.04.1 (Ubuntu)
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
mysql>
Uma vez dentro de sua aplicação, crie o banco de dados:
mysql> create database blog_db;
Declaração de Tabelas
A seguir, escreveremos as tabelas que serão utilizadas em nosso banco de dados.
Caso esteja usando o terminal, acesse seu banco de dados:
mysql> use blog_db;
Uma vez dentro do seu banco de dados, copie cada tabela abaixo e cole em seu terminal.
mysql> show tables;
+-------------------------+
| Tables_in_blog_db |
+-------------------------+
| articles |
| refreshToken |
| user |
+-------------------------+
3 rows in set(0.00 sec)
Por fim, vamos criar um usuário teste com o seguinte comando dentro do banco de dados:
mysql> insert into user(name, password, email, role) values ('admin','admin','admin@admin.com','admin');
Primeiros passos
Iniciando Aplicação
Vamos começar criando o package.json. No terminal de sua escolha:
npm init
Faça a configuração de seu npm init como entender.
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (test)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
Instalando dependências
Em seguida vamos instalar as bibliotecas.
npm i express multer mysql bcryptjs cors dotenv jsonwebtoken
Criando o servidor
Dentro da raiz do projeto, crie o arquivo server.js e adicione o seguinte código:
constexpress=require("express");constcors=require("cors");// connection to the serverconstdbConnection=require("./connection");constrouter=require("./routes/user");// import routsconstuser=require("./routes/user");constarticle=require("./routes/article");constapp=express();// middlewareapp.use(cors());app.use(express.urlencoded({extended:true}));app.use("/uploads",express.static("uploads"));app.use(express.json());constupload=require("./middleware/upload");// declare routsapp.use("/user",user);app.use("/articles",article);// calling serverconstPORT=8080;app.listen(PORT,()=>{{console.log(`server is running at port ${PORT} `);}});
Pode ser que, neste momento, alguns dos arquivos ainda não tenham sido escritos, mas não se preocupe. Mais adiante, iremos criá-los.
Uma vez em que todos os módulos necessários forem instalados e a conexão com o banco de dados configurada corretamente antes de iniciar o servidor
caso queira fazer um teste, comente do código todas as rotas e conexão com banco dedados, deixando apenas o app.listen
Podemos escrever no terminal:
$ node server.js
E nosso servidor irá rodar na porta 8080.
Conexão ao Banco de Dados
Fazendo uso da biblioteca mysql, vamos escrever o código que conectará o nosso servidor ao banco de dados.
Lembre-se de substituir os valores pelos seus exatos para conectar ao banco de dados. Você pode registrá-los em seu arquivo .env para uma melhor proteção.
Crie um arquivo chamado connection.js com o seguinte conteúdo:
constmysql=require("mysql");constdbConfig={host:"localhost",user:"your db user",password:"your db password",database:"your db",};constdbConnection=mysql.createConnection(dbConfig);module.exports=dbConnection;
Middleware
Dentro da pasta middleware, iremos escrever dois arquivos.
Autenticação
Dentro do arquivo middleware/auth.js, escreveremos o sistema responsável por validar a nossa chave de autenticação. Essa função será utilizada para proteger as rotas privadas de nossa aplicação, evitando que os dados de nosso banco de dados sejam acessados por usuários indevidos.
Primeiramente, dentro de nossa pasta raiz, vamos declarar um arquivo .env. Em seguida, dentro desse arquivo, vamos salvar a nossa chave de autenticação.
TOKEN_KEY = "ColoqueAquiOSeuToken"
TOKEN_REFRESH = "InsiraAquiSeuTokenDeVaLiDaçÃo"
TOKEN_LIFE="300" // tempo de vida do token
TOKEN_LIFE_REFRESH="400" // tempo de vida do token refresh
Você pode utilizar o próprio terminal para gerar o seu token. Primeiro, entre no node
O resultado será uma linha composta de números e letras.
Caso queira saber mais sobre jwt, acesse sua documentação.
Agora vamos escrever nossa função verifyToken dentro do arquivo auth.js:
constjwt=require("jsonwebtoken");constconfig=process.env;constverifyToken=(req,res,next)=>{consttoken=req.body.token||req.query.token||req.headers["x-access-token"];if (!token)returnres.status(403).send("a token is required for authentication");try{constdecoded=jwt.verify(token,config.TOKEN_KEY);req.user=decoded;}catch (err){returnres.status(401).send({message:"ivalid token"});}returnnext();};module.exports=verifyToken;
Upload de arquivos
Nosso blog fará uso de imagens na publicação de nossos artigos, para isso, vamos criar um middleware capaz de lidar com o path das imagens e redirecioná-los para uma pasta específica de nossa aplicação: uploads/.
Faremos uso da biblioteca multer, para saber mais, acesse a sua documentação.
Crie um arquivo chamado uploads.js dentro da pasta middleware:
Dentro de utils/, iremos escrever a função truncanteText. Seu uso é simples. A função recebe um texto e retorna dele uma parte pequena. Ela será usada para enviar um pequeno resumo do conteúdo do artigo como consulta de nossa API.
Crie um arquivo chamado truncanteText.js dentro da pasta utils com o seguinte conteúdo:
Se as credenciais estiverem corretas, gera dois tokens JWT: um para o acesso regular (accessToken) e outro para refresh (refreshToken). Os tokens contêm informações sobre o usuário, como id, nome e email. Os tokens são assinados usando chaves secretas definidas nas variáveis de ambiente.
3. /Refresh-Token - Rota para a ré-autenticação de nosso usuário na aplicação.
Coletamos os dados do corpo da solicitação (req.body) relacionados ao novo artigo, como userId, title, e content. Além disso, obtém o caminho da imagem carregada usando o middleware multer e o nome do campo especificado ("thumb").
Escrita da consulta sql para inserir os dados do novo artigo dentro da tablea articles do banco de dados.
Os valores inseridos são obtidos das variáveis userId, title, image, e content.
Defina uma rota HTTP DELETE para "/delete/:id". Esta rota será usada para remover um artigo do banco de dados. A autenticação é verificada antes de permitir a execução desta rota.
Obtém o parâmetro id da URL usando req.params. Este id é usado para identificar o artigo que será removido do banco de dados.
javascript
const id = req.params.id;
Escreva uma consulta sql para excluir um artigo da tabela "articles" do banco de dados com base no id fornecido.
javascript
const query = "delete from articles where id=?";
Aqui está o resultado final do nosso código:
javascript
router.delete("/delete/:id", authentication, (req, res) => {
const id = req.params.id;
const query = "delete from articles where id=?";
dbConnection.query(query, [id], (err, result) => {
if (!err) {
if (result.affectedRows == 0) {
return res.status(404).json({ message: "article id does not found" });
} else {
return res.status(200).json({ message: "article deleted" });
}
} else {
return res.status(500).json(err);
}
});
});
3. /edit/:id - Rota para a edição de Artigos.
Defina uma rota HTTP PATCH para "/edit/:id". Esta rota será usada para atualizar um artigo no banco de dados. A autenticação é verificada antes de permitir a execução desta rota.
5. /getById/:id - Rota para obter um Artigo com base no ID.
Defina uma rota HTTP GET para "/getById/:id".
js
router.get("/getById/:id", (req, res) => {...}
Coletamos o parâmetro id da URL usando req.params.
js
const id = req.params.id;v
Escreva uma consulta sql para selecionar todos os campos do artigo na tabela "articles" do banco de dados onde o id corresponde ao id fornecido na URL.
javascript
const query = "SELECT * FROM articles WHERE id=?";
Aqui temos o resultado final do nosso código:
javascript
router.get("/getById/:id", (req, res) => {
const id = req.params.id;
const query = "SELECT * FROM articles WHERE id=?";
dbConnection.query(query, [id], (err, results) => {
if (err) {
res.status(500).send({ message: "something whent wrong" }, err);
} else if (results.length === 0) {
res.status(404).send({ message: "article not found" });
} else {
res.json(results[0]);
}
});
});
Com todas essas rotas escritas vamos se capazes de consultar, registrar, editar e remover os dados de nossa aplicação.
Conclusão
Primeiramente, gostaria de agradecer por dedicar seu tempo a este tutorial, e parabéns por concluí-lo! Espero que tenha sido útil e fácil de seguir.
Sinta-se à vontade para explorar mais suas habilidades nesta aplicação. Algumas rotas foram deixadas de fora propositalmente para que você se sinta tentado a escrevê-las por si mesmo. Caso não tenha nada em mente, aqui estão algumas sugestões:
Rota para edição dos dados de um usuário
Rota para recuperação de senha de usuário via e-mail.
Rota para atualização de senha de usuário.
Rota para download de um artigo específico em formato markdown.
Este tutorial também abrange a parte frontend de nossa aplicação. Afinal, para que você quer uma API se não for usá-la em algum lugar, não é mesmo? Portanto, avance para a próxima etapa, acesse aqui e continue o nosso tutorial.
Além disso, não deixe de me seguir nas redes sociais.