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
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:
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:
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:
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.
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.
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:
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:
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.
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:
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:
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:
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:
Note que, quando utilizamos o INSERT do MySQL, o connection que criamos nos retorna um resultado diferente de quando estávamos utilizando o SELECT:
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:
Agora teremos a seguinte resposta para a nossa requisição:
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:
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.
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:
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:
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:
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!
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.