Realizando um CRUD no MySQL com o Node.js

Realizando um CRUD no MySQL com o Node.js

Durante o desenvolvimento de uma aplicação robusta em que interagimos com bancos de dados, é uma certeza que o desenvolvedor backend realizará as quatro operações básicas de criação, leitura, atualização e exclusão.

Conhecido como CRUD (abreviação em inglês para as palavras Create, Read, Update e Delete), este é o conjunto de operações com bancos de dados mais crucial para um programador e, diante da sua importância, decidimos trazer neste artigo um passo a passo de como realizar estas quatro ações com o Node.js, utilizando o MySQL2.

O que são o Node.js e o MySQL?

Para o desenvolvimento desta aplicação, utilizaremos o Node.js e o MySQL. Ambos dialogam muito bem entre si, mas cada um tem sua própria área de atuação: enquanto o Node é um interpretador JavaScript que fornece o suporte a esta linguagem tanto no lado cliente quanto do lado servidor, o MySQL é um sistema de gerenciamento de banco de dados que utiliza a linguagem SQL da empresa Oracle, sendo amplamente utilizado para esta funcionalidade nos dias atuais.


Instalando o essencial para o desenvolvimento

Vamos iniciar o nosso projeto criando um diretório onde haverá o arquivo package.json. Também instalaremos o MySQL2 (utilizado para a conexão entre o Node.js e o MySQL), o Express (para organização de requisições e respostas) e o Nodemon (para evitar a necessidade de reiniciar o servidor toda vez que fizermos alguma alteração nos arquivos do projeto). Para isto, basta executar os seguintes comandos em um terminal iniciado na pasta raíz do projeto:

npm init -y

npm install mysql2

npm install express

npm install nodemon

Figura 1 - Arquivo package.json após a inicialização do projeto.


Inicializando o servidor

Precisamos criar um arquivo que será responsável por inicializar o nosso servidor Node. Criaremos então uma pasta chamada src com um arquivo app.js dentro dela:

Figura 2 - Configurações do arquivo app.js.


Explicando melhor o que foi feito no código da figura 2, temos:

  • A importação do Express na linha 1 e a execução do mesmo em uma constante na linha 3;
  • A declaração na linha 5 para a aplicação que serão utilizadas requisições e respostas no Express com o formato JSON;
  • O uso da função listen na linha 9 que recebe como parâmetros uma porta que o servidor funcionará (você pode utilizar qualquer porta que esteja livre) e uma função, que no nosso caso que exibe uma mensagem em tela da porta que está sendo utilizada.

Para inicializar o servidor, precisamos criar um script no campo scripts do arquivo package.json que utilizará o Nodemon para executar o app.js criado. Também é importante alterar a main para o arquivo citado. Se tudo der certo, ao executar o comando npm run dev em um terminal executado na pasta raíz do seu projeto, você terá o seguinte retorno:

Figura 3 - Configurando o package.json e inicializando o servidor.


Configurando a conexão com o banco de dados

Para conectar o Node.js e o MySQL com o uso da biblioteca MySQL2, precisamos fazer o uso de algumas funcionalidades que a ferramenta nos proporciona. Primeiro, criaremos uma pasta chamada connection, com um arquivo index.js que conterá as configurações necessárias para a conexão:

Figura 4 - Configurando a conexão entre o Node.js e o MySQL.


Vamos analisar mais a fundo as implementações feitas na figura 4:

  • O uso do promise na importação do MySQL2 na linha 1 é necessário porque consultas a bancos de dados externos envolvem tratamentos por assincronicidade e, para utilizarmos async e await com a biblioteca, precisamos realizar a importação desta forma;
  • Utilizamos a função createPool do MySQL2 na linha 3 que é responsável por retornar um conjunto de conexões prévias com o banco de dados; essas conexões serão utilizadas ao longo do desenrolar da aplicação para realizar qualquer tipo de interação com o MySQL;
  • Dentro da função createPool informamos o host da nossa aplicação, a porta que o MySQL está sendo executado, o nome do banco de dados e usuário e senha de conexão.
💡
Obs: É possível repassar mais configurações dentro do createPool, mas para a implementação que estamos planejando as utilizadas já são o suficiente.


Criando Rotas

Agora que está tudo pronto para criarmos as primeiras interações com o banco de dados, criaremos uma rota para cada operação CRUD chamada actors. Ela deverá ser criada dentro de uma pasta chamada routes, por questões de organização.

Na rota criada importaremos a função Router pertencente ao Express, executando e exportando a mesma. Também criaremos no nosso arquivo principal app.js a relação desta rota criada com o endpoint /actors.

Figura 5 - Primeiras implementações na rota actors.
Figura 6 - Importando a rota actors no arquivo principal da aplicação.

Informações importantes

Antes de começar de fato a abordar cada operação CRUD em específico, precisamos esclarecer algumas coisas. A primeira informação importante é que utilizaremos neste projeto um banco de dados cedido pelo próprio MySQL, chamado sakila. Você pode fazer o download do arquivo SQL aqui, extraí-lo e importá-lo no seu MySQL. Neste banco de dados, utilizaremos a tabela actor e criaremos um arquivo chamado querys onde todas as requisições ao banco de dados serão feitas, prezando por uma melhor organização do nosso código.

Grande parte das requisições na internet são realizadas utilizando o protocolo HTTP. Este por sua vez, nos disponibiliza diversos métodos (também conhecidos como verbos) de requisições, onde hoje iremos nos resumir a quatro (um para cada operação do CRUD): POST, GET, PUT e DELETE, respectivamente.

Operações CRUD na prática

Leitura com o verbo GET

Para exibir todos os elementos que compõem a tabela actor, utilizaremos o método get, usado neste caso para exibir as informações que serão devolvidas pela consulta ao banco de dados.

Vamos focar primeiro nesta interação com o banco. Importaremos a connection que criamos e utilizaremos a função execute, responsável por enviar como parâmetro uma consulta MySQL:

Figura 7 - Configurando a query que retorna todos os items da tabela actors.


Note na figura 7 que houve uma desestruturação do valor que é recebido pela consulta da linha 4. Isto acontece porque a resposta devolvida por esta query é um array com várias informações, onde a primeira posição armazena os dados que foram retornados com a consulta.

Agora, precisamos executar o método get da função router na rota actors. Esta função recebe como parâmetros um endpoint e uma função que, por sua vez, recebe a requisição e a resposta deste endpoint. É dentro dela que executamos a função getAllActors e a retornamos como uma resposta de status 200 e formato json:

Figura 8 - Criando o método get da rota actors.
Figura 9 - Retorno da requisição do método get da rota actors.
💡
Obs: O software utilizado na figura 9 para simular requisições foi o Insomnia, mas você pode utilizar outros que achar mais familiarizado/a.


Também é possível utilizar o método get para retornar determinado item de acordo com determinado parâmetro encaminhado via endpoint. Imaginemos que neste endpoint enviaremos um id, sendo o item com este id o único a ser exibido. Primeiro, criamos o parâmetro no endpoint utilizando dois pontos (:) e depois o nome que daremos a ele. Este parâmetro ficará salvo em params, que fica dentro da requisição recebida pelo método get.

Figura 10 - Método que utiliza parâmetro do endpoint.


Criamos uma lógica de programação que, caso o id enviado não seja encontrado, retornaremos uma mensagem actor not found. Do contrário, o item com o id encontrado será retornado.

Agora, precisamos criar uma função que recebe o id como parâmetro e faz uma consulta no banco de dados, retornando um item que tenha o id igual ao recebido:

Figura 11 - Criação da função getActorsById.
Figura 12 - Resposta retornada de acordo com o parâmetro encaminhado.

Criação com o verbo POST

Chegou a hora de criarmos o método que adiciona uma nova pessoa à tabela actors. Desta vez, utilizaremos o método post, normalmente utilizado para esta ação de criação.

O post é utilizado para enviar de forma mais segura do que enviando pelo endpoint, como fizemos no método get. Suponha que para fazer um novo cadastro na tabela actor precisamos enviar os dados de primeiro e um último nome. Desta forma, teremos a seguinte requisição:

Figura 13 - Criação da função getActorsById.


Para melhor compreensão e abstração do que está ocorrendo, imagine que o nosso frontend está encaminhando para nós os dois dados de primeiro e último nome que serão necessários para o cadastro, por meio de dois inputs que foram preenchidos pelo usuário.

Podemos acessar o que é encaminhado pelo corpo da requisição por meio do objeto body, que por sua vez é acessado pela requisição do método. Veja:

Figura 14 - Método post que recebe dois dados como parâmetro.

Agora que o método post foi criado, vamos criar a função createActor. Ela precisa receber os dois parâmetros first_name e last_name e inseri-los na tabela actor:

Figura 15 - Função createActor.

Note que, quando utilizamos o INSERT do MySQL, o connection que criamos nos retorna um resultado diferente de quando estávamos utilizando o SELECT:

Figura 16 - Resposta do comando INSERT do MySQL.


Este objeto retornado nos traz algumas informações importantes, como o número de linhas afetadas com a nossa ação e o id que foi inserido para o item cadastrado. Sendo assim, por que ao invés de retornarmos este objeto, não retornamos o item completo que foi cadastrado, com todas as colunas que ele possui? Podemos inclusive utilizar a função getActorsById para isto:

Figura 17 - Alterando a função createActor para retornar a linha cadastrada.

Agora teremos a seguinte resposta para a nossa requisição:

Figura 18 - Novo retorno para a função createActor.

Atualização com o verbo PUT

Para atualizar um item existente na tabela, utilizaremos o método put, que geralmente é utilizado para realizar requisições de atualização. Genericamente falando, usamos o put quando é necessário enviar uma informação e não fazer nenhuma outra ação além de armazená-la. A criação do método não será muito diferente do que já fizemos anteriormente:

Figura 19 - Criação do método put.


Desta vez, estamos esperando que no corpo da requisição sejam enviados três campos: id, first_name e last_name. O que faremos na função de interação com o banco de dados será alterar os valores das colunas first_name e last_name na linha que possuir um actor_id igual ao id fornecido.

Figura 20 - Função updateActor.


Note que primeiro verificamos se o id encaminhado existia na tabela, retornando null caso não existisse. Desta forma, evitamos uma tentativa de atualização que não surtaria efeito.

Exclusão com o verbo DELETE

Por fim, chegamos na última operação do CRUD. Para realizar a exclusão utilizaremos o verbo DELETE, utilizado para requisições que visam deletar alguma informação. Para isto, receberemos um id no corpo da requisição e o utilizaremos para excluir a linha da tabela que possuir um actor_id igual ao parâmetro encaminhado:

Figura 21 - Criação do método delete.


Da mesma forma como fizemos no método put, primeiro devemos verificar se existe alguma linha da tabela que possua o id mencionado, para só depois executar o comando de exclusão:

Figura 22 - Função deleteActor.


Execute o código a seguir e note que a aplicação apresentará o erro descrito abaixo:

cannot delete or update a parent row: a foreign key constraint fails (`sakila`.`film_actor`, CONSTRAINT `fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES `actor` (`actor_id`) ON DELETE RESTRICT ON UPDATE CASCADE)

O erro acontece porque existe uma foreign key em outra tabela do sakila que depende diretamente do campo actor_id da tabela actor. Este relacionamento entre as duas colunas foi criado com uma restrição que impede que uma linha de actor seja deletada sem que seus dependentes também o sejam.

Este erro não aconteceria se, no método de criação da tabela, fosse utilizado um ON DELETE CASCADE ao invés de um ON DELETE RESTRICT. Para resolver o problema, basta excluir primeiro o campo da tabela film_actor (que é a origem do erro, como podemos ver na descrição do erro retornado) que tem relação direta com o actor_id que queremos excluir:

Figura 23 - Alteração do método delete para a restrição existente na tabela.


Considerações finais

Neste artigo, aprendemos como criar, ler, alterar e apagar itens em um banco de dados utilizando a interação entre o Node.js e o MySQL. A partir dos verbos POST, GET, PUT e DELETE, vimos as formas de requisição e as respostas recebidas para cada um dos métodos, bem como algumas formas de consulta no MySQL para que a interação fosse realizada de forma efetiva.

Espero que você tenha aprendido sobre o CRUD e quero saber aqui nos comentários o que você achou de praticar estas operações. Bons estudos!

💡
As opiniões e comentários expressos neste artigo são de propriedade exclusiva de seu autor e não representam necessariamente o ponto de vista da Revelo.

A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.