Hoje vou ensinar como que você pode usar Node.js com MySQL. Apesar de MongoDB e demais bases não relacionais serem a escolha mais comum com Node, muitos programadores, geralmente de background PHP, conhecem e usam MySQL e não querer abrir mão de seu conhecimento a respeito.
Além disso, como pessoal da Rising Stack afirma, com bons índices e planejamento adequado, o MySQL pode ser excelente. Sendo assim, acredito que este post ajudará quem estiver migrando de plataforma, mas não quer migrar de banco.
Existem diversas maneiras de usar MySQL com Node. Uma vez que é um banco de dados muito popular, logo, é possível que você encontre muita informação diferente na Internet à respeito. Entenda que te mostrarei UMA das INÚMERAS opções de como conectar no MySQL com Node.js.
Também é importante salientar que parto do pressuposto que você já saiba usar MySQL, já tem uma base criada na sua máquina ou em algum provedor (recomendo a Umbler) e que também já saiba o básico de Node.js. Vou me focar aqui em “ligar as pontas”.
Para um tutorial ainda mais iniciante que esse, sugiro este.
Caso ainda não tenha sequer instalado o MySQL na sua máquina, este vídeo pode ajudar.
Se preferir, pode assistir ao vídeo abaixo ao invés de ler o tutorial.
Então vamos lá!
Criando o Projeto
Crie uma pasta para o projeto, com o nome que quiser.
Dentro, crie um db.js e um index.js, ambos vazios.
Abra o terminal e dentro dessa pasta rode um npm init para inicializar o projeto e criar o package.json.
Ainda no terminal, mande instalar a dependência mysql2, como abaixo.
1 2 3 |
npm i mysql2 |
Por que mysql2 e não o pacote mysql padrão?
Porque o mysql2 possui uma performance muito superior e suporte a Promises, o que nos permite escrever um código JavaScript mais moderno e elegante.
Dito isso, vamos em frente!
Criando a conexão
Agora vamos abrir o nosso db.js e criar a conexão com nosso banco de dados, usando o pacote que acabamos de instalar. Vou largar o código, e explico na sequência.
1 2 3 4 5 6 7 8 9 10 11 12 |
async function connect(){ if(global.connection && global.connection.state !== 'disconnected') return global.connection; const mysql = require("mysql2/promise"); const connection = await mysql.createConnection("mysql://root:luiztools@localhost:3306/crud"); console.log("Conectou no MySQL!"); global.connection = connection; return connection; } |
Ignore o primeiro if, vamos para o ‘const mysql’. Nós começamos a conexão carregando o nosso pacote, mais especificamente o wrapper mysql2/promise que é justamente o que nos dá o suporte a Promises que comentei antes. Caso queira entender o que são promises, este artigo explica (inclui vídeo).
Com esta constante mysql, consigo chamar a function createConnection que espera a nossa connection string com o banco. Aqui você deve substituir pelos dados da sua instalação de MySQL, no formato mysql://usuario:senha@servidor:porta/banco
Note que usei a palavra reservada await antes do createConnection. Isso porque o createConnection é assíncrono, o que me obriga a usar callback, promise ou async/await para garantir que a instrução a seguir só aconteça depois da conexão já estabelecida.
Optei pelo await por ser a forma mais moderna (ES6), mas ele me obriga a usar a keyword async antes da declaração da minha function, como deve ter reparado também.
No fim da function de conexão, eu armazeno ela em uma variável global e agora sim faz sentido eu lhe explicar o primeiro if do código.
Como eu não quero ficar criando um monte de conexões com o MySQL (isso é lento e consome muitos recursos do servidor), eu vou criar apenas uma, compartilhar em uma variável global e, quando a conexão for chamada pela segunda vez, ela vai cair naquele if inicial que verifica se já não existe uma conexão global conectada. Se existir, ela vai ser reaproveitada ao invés de criar uma nova.
Uma técnica mais avançada que essa é usando pool de conexões, ou mesmo um ORM (como o Sequelize), mas que fogem do escopo deste post mais introdutório.
Para testar este código, crie uma chamada a esta conexão ao fim do módulo e importe-o no index.js, para dispará-la.
1 2 3 4 |
//index.js const db = require("./db"); |
Como resultado, irá imprimir no console a mensagem de que se conectou com sucesso no MySQL.
SELECT
Certo, fizemos a conexão, e agora como vamos utilizá-la para fazer um CRUD básico no MySQL?
No mesmo módulo db.js, cria outra function, desta vez para select, logo abaixo da anterior.
1 2 3 4 5 6 7 8 9 |
async function selectCustomers(){ const conn = await connect(); const [rows] = await conn.query('SELECT * FROM clientes;'); return rows; } module.exports = {selectCustomers} |
Esta função é beeem mais simples que a outra. Nela, nós realizamos a conexão (que internamente vai decidir reaproveitar ou não) e depois usamos a função query com este objeto connection recém criado.
O SQL em si dispensa aplicações, mas se precisar de ajuda vou recomendar um vídeo a seguir. O retorno do query é um array de arrays cheio de coisas, onde queremos somente o array nomeado rows, que traz as linhas resultantes da consulta.
Note o uso de await para que fique mais fácil de gerenciar tanto o retorno da conexão quanto o retorno da query, deixando-os visualmente síncronos (eles não deixam de ser assíncronos, é apenas efeito visual ou syntax sugar).
No fim do módulo, diferente da função de connect, exportamos esta função pois queremos usar ela no nosso index.js.
Falando nele…
1 2 3 4 5 6 7 8 9 10 11 |
//index.js (async () => { const db = require("./db"); console.log('Começou!'); console.log('SELECT * FROM CLIENTES'); const clientes = await db.selectCustomers(); console.log(clientes); })(); |
Note que dei uma incrementada boa aqui, mas nada muito complicado.
Primeiro, temos o require do nosso db, uns logs de marcação e na sequência chamo a função de selectCustomers exportada no módulo db que vai retornar o nosso array de clientes, que vou só jogar no console, mas que em uma aplicação real tenho certeza que você será mais criativo.
Como estou usando o await aqui também, e ele existe ser usado em funções async, criei uma função async anônima ao redor de todo código que automaticamente é chamada quando mandarmos executar o index.js.
Faça isso agora e verá que funciona como deveria, printando no console todos os clientes do seu banco de dados, tabela clientes.
Não faz nem ideia do que é ou como criar uma tabela? O vídeo abaixo é perfeito para isso.
INSERT
Agora é hora de inserirmos clientes no MySQL via JavaScript!
Volte ao nosso db.js e insira uma nova função.
1 2 3 4 5 6 7 8 |
async function insertCustomer(customer){ const conn = await connect(); const sql = 'INSERT INTO clientes(nome,idade,uf) VALUES (?,?,?);'; const values = [customer.nome, customer.idade, customer.uf]; return await conn.query(sql, values); } |
Esta função tem algumas novidades em relação à anterior.
primeiro, o SQL possui conteúdo dinâmico, que são os valores a serem inseridos na linha da tabela clientes. E embora seja muito tentado concatenar a string SQL na mão, não faça isso sob risco de SQL Injection!
Ao invés disso, coloque ‘?’ no lugar dos campos em quando chamar o conn.query, o segundo parâmetro aceita um array de valores que serão corretamente substituídos na sua string SQL, já prevendo SQL Injection.
No mais, a construção desta função segue a regra das anteriores e não esqueça de exportá-la no seu db.js para usarmos no index.js, como abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//index.js (async () => { const db = require("./db"); console.log('Começou!'); console.log('INSERT INTO CLIENTES'); const result = await db.insertCustomer({nome: "Zé", idade: 18, uf: "SP"}); console.log(result); console.log('SELECT * FROM CLIENTES'); const clientes = await db.selectCustomers(); console.log(clientes); })(); |
Optei por colocá-lo antes do SELECT, para que fique mais fácil de ver se ele funcionou ou não.
Também optei por printar o seu resultado, para você ver o que ele devolve, embora a maior parte das informações não seja muito útil, somente o número de linhas afetadas na tabela talvez lhe interesse pois, no fundo, se der algum erro na execução do SQL, vai disparar uma exception que vai derrubar essa nossa aplicação bem simples. Sim, você pode embrulhar tudo com try/catch para tratar os erros.
UPDATE
Avançando rapidamente, pois acredito que agora você já “pegou a manha”, o updateCustomer ficaria como abaixo.
1 2 3 4 5 6 7 8 |
async function updateCustomer(id, customer){ const conn = await connect(); const sql = 'UPDATE clientes SET nome=?, idade=?, uf=? WHERE id=?'; const values = [customer.nome, customer.idade, customer.uf, id]; return await conn.query(sql, values); } |
Note o mesmo padrão de construção do INSERT, com a leve diferença que o update requer um ID, importantíssimo nesse tipo de comando SQL.
E no index.js, seguimos a mesma estrutura do INSERT também, apenas tome cuidado para informar um ID existente na sua base de dados ao invés do meu ‘6’, ou até mesmo modifique o código para pegar um dos ids retornados pelo SELECT anterior.
1 2 3 4 5 |
console.log('UPDATE CLIENTES'); const result2 = await db.updateCustomer(6, {nome: "Zé José", idade: 19, uf: "SP"}); console.log(result2); |
DELETE
E para finalizar, nosso deleteCustomer no db.js.
1 2 3 4 5 6 7 8 9 |
async function deleteCustomer(id){ const conn = await connect(); const sql = 'DELETE FROM clientes where id=?;'; return await conn.query(sql, [id]); } module.exports = {selectCustomers, insertCustomer, updateCustomer, deleteCustomer} |
Aqui, ficou ainda mais simples que nos anteriores e o nosso index.js teve apenas mais uma adição que é mais do mesmo.
1 2 3 4 5 |
console.log('DELETE FROM CLIENTES'); const result3 = await db.deleteCustomer(7); console.log(result3); |
O resultado de todos esses códigos e testes?
Uma tabela clientes cheia de Zés, hahaha
Espero que tenha gostado do post e até a próxima!
Uma dica de próxima leitura, aprenda a usar o Sequelize, um famoso ORM para Node.js com suporte a MySQL e aprenda a fazer autenticação em suas aplicações com Passport. Se você quer aprender a publicação aplicação Node.js+MySQL na AWS, este é o tutorial certo.
Curtiu o post? Então clica no banner abaixo e dá uma conferida no meu livro sobre programação web com Node.js com MySQL!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.
Olá Luiz, excelente tutorial, sou iniciante na programação de api’s e web e tenho uma dúvida. Eu estou fazendo uma api que vai ser consumida pelo facebook, e então preciso rodá-la na web. Qual a melhor maneira de fazer isso e o que muda no meu código?
Bom dia Fernando. Primeiramente agradeço pelo comentário. Você tem de ler a documentação de como o Facebook vai consumir sua API e fornecer os endpoints adequados à ele. Não há uma resposta pronta para a “melhor maneira” de fazer isso, vai depender muito do que é sua API, do volume de requisições que vai ter de atender, do tamanho da base, do seu conhecimento atual de programação, etc. Varia muito de cenário para cenário.
Se a sua dúvida é sobre quais tecnologias usar, pegue alguma web que lhe faça confortável e produtivo e fique com ela. Uma ideia é usar Node, mas é só uma ideia, existem várias outras. Pra rodar na web é só hospedar em algum provedor, como a Umbler.
Se puder me fornecer mais detalhes da aplicação, de repente consigo te ajudar melhor.
Certo, então vou tentar explicar. Estou construindo um chatbot através da plataforma chatfuel, e esse chatbot vai enviar dados no formato json para minha api, e também beber dados da mesma, tudo em json. Logo preciso construir a api, e eu fiz este tutorial, deu tudo certo rodando local, mas agora preciso subir essa api para que o chatfuel posso conversar com ela, ai que está a dúvida pois não sei como. O tráfego de dados não vai ser muito grande, pois são poucas informações.
Ah bom, então é tranquilo. Cria uma conta na Umbler, cria um site Node.js nela, cria um banco MySQL, atualiza tua aplicação para apontar pro banco novo e faz deploy dela usando Git. Se quiser migrar dados pro banco, pode fazê-lo via MySQL Workbench ou outras ferramentas visuais similares.
O ideal é que tu registre um domínio próprio, mas se não tiver grana (custa na faixa de R$30/ano), a Umbler te fornece um domínio de teste que tu pode usar indefinidamente.
Qualquer coisa chama eles no chat de suporte que eles te ajudam.
Certo, luiz até ai eu consegui, minha api(rodando localmente) ja está apontando para o banco(na umbler), agora é só eu subir meu app pra umbler? Não preciso mudar nada no código? tipo porta ou ip?
Se a API está rodando “padrão”, ela já está na porta “correta” que é a 3000. É só fazer push pra Umbler que vai funcionar de boa. Daí tu pode testar no navegador usando teu domínio próprio ou endereço de teste que eles te fornecem.
Muito Bakana!… parabens Luiz… me animou bastante utilizar o node… e enfim, uma api pratica e direta!
Obrigado pelo feedback Silvio. Tendo ideia de novos posts ou dúvidas de Node, pode me mandar por email.
Luiz, primeiro gostaria de parabenizer pelo ótimo artigo!
Caí aqui no seu site depois de pesquisar sobre um erro que estou tendo com a conexão com o MySQL. E por uma feliz coincidência, você utiliza a plataforma da Umbler no exemplo e exatamente ela que estou usando o BD. O meu erro acontece na metade da Parte 2, onde executo o teste de conexão do banco, eu conecto normalmente mas após uns 30 segundos a conexão cai e consequentemente a minha aplicação também.
Você pode me dar uma ajuda aqui? Segue o print do erro.
https://uploads.disquscdn.com/images/c34c92fa45ec6bdcf4764d3068a9fbe226a288b9c83caf57323f909a50c15e81.jpg
Aliás, esse erro não ocorre quando eu faço a conexão com o meu banco local.
A Umbler fecha as conexões MySQL ociosas depois de alguns segundos, para evitar que você atinja o limite de conexões e isso prejudique o seu site. Neste caso, terá de abrir e fechar as conexões a cada requisição ao banco. Acho que no código fonte de exemplo deste tutorial eu faço isso.
Entendo. Muito obrigado pelo esclarecimento e a dica =)
Cara muito foda o artigo, parabéns ai
Fico feliz que tenha gostado. Assim como esse, existem diversos outros tutoriais de Node.js aqui no blog.
Muito bom segui aqui deu tudo certo, excelente artigo, hoje uso um servidor
feito em java fiquei bem tentado no node.js.
estou com problemas na hora de acessar o servidor externo da umbler retorna
Error: connect ETIMEDOUT
Está dando time out na conexão. Você consegue conectar usando ferramentas com MySQL Workbench? Está usando os dados de servidor externo mesmo? Já falou com o suporte deles?
sim consigo, me conectar usando ferramentas com MySQL Workbench. mas sò local host,
usando umbler não https://uploads.disquscdn.com/images/28a0eb926a00fc3a1272b8055ab3adf0616103080ead88c023659cc338142805.png
Provavelmente você está com acesso remoto bloqueado. Vá no seu banco MySQL na Umbler, clique em editar e chaveie para permitir acesso externo.
já fiz e o erro continua.
Então sugiro entrar em contato com o suporte deles, não tenho como lhe ajudar com problemas de infraestrutura, só de código.
Excelente!! Consegui muito rapidamente!!
Fico feliz que tenha conseguido fazer funcionar!