O Node.js geralmente é acoplado ao MongoDB e outros bancos de dados NoSQL, mas também funciona bem com bancos de dados relacionais como o MySQL. Caso você queira escrever um novo microsserviço com Node.js para um banco de dados existente, é altamente provável que o banco de dados existente seja o banco de dados de código aberto mais popular do mundo, MySQL.

Neste tutorial, veremos como podemos construir uma API REST com MySQL como banco de dados e Node.js como nossa linguagem. Para tornar nossa tarefa mais fácil, usaremos o framework Express.js. Vamos começar!

Pré-requisitos

Abaixo estão algumas suposições que estamos fazendo antes de entrarmos no código:

  1. Você tem um bom entendimento de como o MySQL e os bancos de dados relacionais funcionam em geral.
  2. Você tem conhecimento básico de Node.js e alguma compreensão da estrutura Express.js.
  3. Você está ciente de quais APIs de REST (transferência de estado representacional) são e como geralmente funcionam.
  4. Você sabe o que é CRUD (criar, ler, atualizar, excluir) e como ele se relaciona com os métodos HTTP GET, POST, PUT e DELETE.

Todo o código será feito em um Mac com o Node 14 LTS instalado. Se quiser, você pode tentar usar Node.js e Docker e docker-compose para uma melhor experiência de desenvolvedor.

introdução rápida e configuração do MySQL

MySQL é um dos bancos de dados mais populares do mundo, senão o mais popular. De acordo com a pesquisa Stack Overflow de 2020, era o banco de dados mais amado, com mais de 55 por cento dos entrevistados usando. A edição da comunidade está disponível gratuitamente e é apoiada por uma comunidade grande e ativa também.

O MySQL é um banco de dados relacional repleto de recursos lançado pela primeira vez em 1995. Ele é executado em todos os principais sistemas operacionais, como Linux, Windows e macOS. Por causa de seus recursos e economia, ele é usado tanto por grandes empresas quanto por novas startups.

Para nossa API REST de linguagens de programação de exemplo, em vez de configurar um servidor MySQL local, usaremos um serviço MySQL gratuito. Usaremos db4free.net para hospedar nosso banco de dados MySQL de teste.

Registre-se em FreeDb.tech

Você pode se registrar em Freedb.tech para colocar seu banco de dados MySQL 8.0 gratuito em funcionamento, executando as seguintes etapas.

Primeiro, vá para a página de inscrição do Freedb, preencha os detalhes como abaixo e clique em Inscrever-se :

exibição da página de inscrição Freedb.tech

Você receberá um e-mail para verificar o seu endereço de e-mail. Depois de clicar nesse link, você pode criar um banco de dados da seguinte maneira:

Criar banco de dados Visual Freed.b

Depois de clicar em Criar banco de dados , desde que o nome do banco de dados seja exclusivo, ele será criado. Você pode tentar usar seu nome para mantê-lo exclusivo. Se tudo correr bem, você verá algo como abaixo, com todas as credenciais para se conectar ao banco de dados recém-criado:

Criar Credenciais de Saída de Banco de Dados

Copie o nome de usuário, a senha e o nome do banco de dados-nós os usaremos na próxima etapa. Em seguida, clique no botão Visitar phpMyAdmin .

Posteriormente, no login do phpMyAdmin, utilize o nome de usuário e senha da tela anterior e clique em Ir , como abaixo:

Visit-phpMyAdmin-login-screen

Crie a tabela de linguagens de programação

Ótimo, seu banco de dados vazio foi criado. Agora vamos adicionar a tabela programming_languages ​​. Para fazer isso, clique no nome do banco de dados à esquerda; para mim, foi freedbtech_language . Em seguida, clique em SQL no menu superior (segundo link após Estrutura ) e coloque o seguinte CREATE TABLE SQL na área de texto:

 CRIAR TABELA `linguagem_de_programação`
( `id` INT (11) NÃO NULO auto_incremento, `nome` VARCHAR (255) NÃO NULO, `release_year` INT NOT NULL, `githut_rank` INT NULL, `pypl_rank` INT NULL, `tiobe_rank` INT NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME em UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE `idx_name_unique` (` nome` (255))
)
engine=innodb charset=utf8mb4 COLLATE utf8mb4_general_ci;

Depois disso, clique no botão Ir , conforme abaixo:

PhpMyAdmin Go Button Output Freedbtech Language

Ele voltará com uma caixa de seleção verde e uma mensagem como MySQL retornou um conjunto de resultados vazio (ou seja, zero linhas) .

Viva! Criamos uma tabela chamada programming_languages ​​ com oito colunas. Ele tem uma chave primária chamada id , que é uma internet e auto-incremento. A coluna name é única.

Também adicionamos release_year para a linguagem de programação. Temos três colunas para inserir a classificação da linguagem de programação:

  • GitHut -estatísticas de idioma do GitHub para o quarto trimestre de 2020
  • PYPL -A popularidade do índice de linguagem de programação
  • Índice TIOBE

As colunas created_at e updated_at são datas para manter um controle de quando as linhas foram criadas e atualizadas. Principalmente, queremos criar uma API das linguagens de programação mais populares, conforme postado nas três fontes acima.

Adicionar 16 linhas de demonstração

A seguir, inseriremos 16 das linguagens de programação populares em nossa tabela linguagem_de_programação . Clique no mesmo link SQL na parte superior e copie/cole o SQL abaixo:

 INSERT INTO programming_languages ​​(id, name, Release_year, githut_rank, pypl_rank, tiobe_rank)
VALORES
(1,'JavaScript', 1995,1,3,7),
(2,'Python', 1991,2,1,3),
(3,'Java', 1995,3,2,2),
(4,'TypeScript', 2012,7,10,42),
(5,'C #', 2000,9,4,5),
(6,'PHP', 1995,8,6,8),
(7,'C ++', 1985,5,5,4),
(8,'C', 1972,10,5,1),
(9,'Ruby', 1995,6,15,15),
(10,'R', 1993,33,7,9),
(11,'Objective-C', 1984,18,8,18),
(12,'Swift', 2015,16,9,13),
(13,'Kotlin', 2011,15,12,40),
(14,'Go', 2009,4,13,14),
(15,'Rust', 2010,14,16,26),
(16,'Scala', 2004,11,17,34);

Deve ser algo como 16 linhas inseridas .

Eu coletei a classificação das linguagens de programação de todas as três fontes acima: GitHut, PYPL e o Índice TIOBE. Os dados coletados são tabulados na instrução de inserção em massa acima. Isso cria 16 linhas para as 16 linguagens de programação acima na tabela que acabamos de criar. Usaremos isso em etapas posteriores, quando buscarmos dados para o endpoint da API GET.

Se clicarmos na tabela programming_languages ​​ visível à esquerda, veremos as linhas que acabamos de adicionar da seguinte maneira:

Tabela de linguagens de programação Novas linhas visual

Na próxima etapa, configuraremos Express.js para nossa API REST de linguagens de programação mais populares com Node.js e MySQL.

Configure Express.js para API REST

Para configurar um aplicativo Node.js com um servidor Express.js, criaremos um diretório para nosso projeto residir em:

 mkdir programming-language-api && cd programming-language-api 

Então podemos fazer um npm init-y para criar um arquivo package.json como abaixo:

 { "name":"programming-langugages-api", "versão":"1.0.0", "description":"Uma API REST de demonstração com Node.js Express.js e MySQL para as linguagens de programação mais populares", "main":"index.js", "scripts": { "test":"echo \"Erro: nenhum teste especificado \"&& exit 1" }, "repositório": { "tipo":"git", "url":"git + https://github.com/geshan/programming-langugages-api.git" }, "palavras-chave": [], "autor":"", "licença":"ISC", "insetos": { "url":"https://github.com/geshan/programming-langugages-api/issues" }, "homepage":"https://github.com/geshan/programming-langugages-api#readme"
}

Para nossa facilidade, todo o código passo a passo será uma sequência de solicitações de pull . Conseqüentemente, instalaremos o Express.js executando npm i--save express . Isso adiciona Express como uma dependência no arquivo package.json .

A seguir, criaremos um servidor slim no arquivo index.js . Irá imprimir uma mensagem ok no caminho principal /, como abaixo:

 const express=require ('express');
const bodyParser=require ('body-parser');
const app=express ();
porta const=3000; app.use (bodyParser.json ());
app.use ( bodyParser.urlencoded ({ extendido: verdadeiro, })
); app.get ('/', (req, res)=> { res.json ({'mensagem':'ok'});
}) app.listen (porta, ()=> { console.log (`Exemplo de aplicativo ouvindo em http://localhost: $ {port}`)
});

Precisamos tomar nota de algumas coisas neste momento:

  1. Estamos usando o middleware de analisador de corpo para analisar JSON que usaremos nas próximas etapas.
  2. Também estamos utilizando a função bodyParser.urlencoded para analisar o corpo codificado do URL.
  3. O aplicativo será executado na porta 3000 se PORT não for fornecida como uma variável de ambiente.

Podemos executar o servidor com node index.js e clicar em http://localhost: 3000 para ver {message:"ok"} como saída.

Estrutura do projeto

Estruturaremos nosso projeto da seguinte maneira, para que os arquivos sejam dispostos de forma lógica em pastas:

Node.js App Project Structure Folder Layout

Vamos dar uma olhada rápida na estrutura da API de linguagens de programação populares que vamos construir:

  1. config.js terá configurações como as credenciais do banco de dados e linhas por página que queremos mostrar quando paginamos os resultados.
  2. helper.js é o lar de todas as funções auxiliares, como o cálculo de deslocamento para paginação.
  3. O arquivo routes/programmingLanguages.js agirá como a cola entre o URI e a função correspondente no serviço services/programmingLanguages.js .
  4. A pasta services abrigará todos os nossos serviços. Um deles é o db.js , usado para falar com o banco de dados MySQL.
  5. Outro serviço é programmingLanguages.js , que terá métodos como getMultiple , create , etc. para obter e criar o recurso de linguagem de programação. O mapeamento básico do URI e da função de serviço relacionada será semelhante a seguir:
    1. GET/linguagem de programação → getMultiple()
    2. POST/linguagens de programação → criar()
    3. PUT/programming-languages ​​/: id → update()
    4. DELETE/programming-languages ​​/: id → remove()

Agora vamos codificar nossa API de linguagens de programação GET com paginação.

OBTER linguagens de programação populares

Para criar nossa API de linguagens de programação GET, precisaremos vincular nosso servidor Node.js ao MySQL. Para fazer isso, usaremos o pacote npm mysql2 . Podemos instalar o pacote mysql2 com o comando npm i--save mysql2 na raiz do projeto.

A seguir, criaremos o arquivo config na raiz do projeto com o seguinte conteúdo:

 const env=process.env; const config={ bd: {/* não exponha a senha ou qualquer informação sensível, feito apenas para demonstração */ host: env.DB_HOST ||'freedb.tech', usuário: env.DB_USER ||'freedbtech_geshan-lr', senha: env.DB_PASSWORD ||'G2VjjQ5d47zyjqX', banco de dados: env.DB_NAME ||'freedbtech_language', }, listPerPage: env.LIST_PER_PAGE || 10,
}; module.exports=config;

Consequentemente, criaremos o helper.js com o código abaixo:

 function getOffset (currentPage=1, listPerPage) { return (currentPage-1) * [listPerPage];
} function emptyOrRows (rows) { if (! linhas) { Retorna []; } retornar linhas;
} module.exports={ getOffset, emptyOrRows
}

Em seguida, fazemos a parte divertida de adicionar a rota e vinculá-la aos serviços. Primeiro, vamos nos conectar ao banco de dados e permitir a execução de consultas no banco de dados no services/db.js :

 const mysql=require ('mysql2/promessa');
const config=require ('../config'); consulta de função assíncrona (sql, params) { conexão const=espera mysql.createConnection (config.db); const [resultados,]=espera conexão.executar (sql, params); resultados de retorno;
} module.exports={ consulta
}

Consequentemente, iremos escrever o arquivo services/programmingLanguage.js que atua como a ponte entre a rota e o banco de dados da seguinte maneira:

 const db=require ('./db');
const helper=require ('../helper');
const config=require ('../config'); função assíncrona getMultiple (página=1) { const offset=helper.getOffset (página, config.listPerPage); const rows=await db.query ( `SELECT id, name, release_year, githut_rank, pypl_rank, tiobe_rank FROM linguagem_de_programação LIMIT?,? `, [deslocamento, config.listPerPage] ); dados const=helper.emptyOrRows (linhas); const meta={página}; Retorna { dados, meta }
} module.exports={ getMultiple
}

Depois disso, criamos o arquivo routes em routes/programmingLanguages.js , que se parece com isto:

 const express=require ('express');
roteador const=express.Router ();
const programmingLanguages ​​=require ('../services/programmingLanguages'); /* Linguagens de programação GET. */
router.get ('/', função assíncrona (req, res, próximo) { tentar { res.json (await programmingLanguages.getMultiple (req.query.page)); } catch (errar) { console.error (`Erro ao obter linguagens de programação`, err.message); próximo (errar); }
}); módulo.exportações=roteador;

A última parte para que nosso endpoint de linguagem de programação GET ganhe vida é conectar a rota no arquivo index.js da seguinte maneira:

 const express=require ('express');
const bodyParser=require ('body-parser');
const app=express ();
const port=process.env.PORT || 3000;
const programmingLanguagesRouter=require ('./routes/programmingLanguages'); app.use (bodyParser.json ());
app.use ( bodyParser.urlencoded ({ extendido: verdadeiro, })
); app.get ('/', (req, res)=> { res.json ({'mensagem':'ok'});
}) app.use ('/programming-languages', programmingLanguagesRouter); /* Middleware do manipulador de erros */
app.use ((err, req, res, próximo)=> { const statusCode=err.statusCode || 500; console.error (err.message, err.stack); res.status (statusCode).json ({'mensagem': err.message}); Retorna;
}); app.listen (porta, ()=> { console.log (`Exemplo de aplicativo ouvindo em http://localhost: $ {port}`)
});

As duas principais mudanças em nosso arquivo index.js do ponto de entrada são:

 const programmingLanguagesRouter=require ('./routes/programmingLanguages');

E vinculando a rota /programming-languages ​​ ao roteador que acabamos de criar da seguinte maneira:

 app.use ('/programming-languages', programmingLanguagesRouter);

Também adicionamos um middleware de manipulador de erros para lidar com quaisquer erros e fornecer um código de status adequado e uma mensagem em caso de erro.

Depois de adicionar o endpoint GET, quando executamos nosso aplicativo novamente com node index.js e acertamos o navegador com http://localhost: 3000/programming-languages ​​ , veremos uma saída como esta:

Obter Endpoint com Node Index.js Output

Dependendo das extensões que você instalou em seu navegador, você pode ver a saída de forma um pouco diferente.

Outra coisa boa é a paginação para esta API GET já ter sido implementada-tente http://localhost: 3000/programming-languages? page=2 para ver as linguagens de 11 a 16.

Esta paginação é possível devido ao getOffset função em helper.js e a forma como executamos a consulta SELECT em services/programmingLanguage.js . Vou deixar você com algum tempo para examinar o código acima para obter uma melhor compreensão de como ele é montado.

Na próxima etapa, codificaremos a API POST de criação de linguagem de programação.

POSTAR uma nova linguagem de programação

Para criar uma API de linguagem de programação POST no ponto de extremidade /programming-languages ​​, adicionaremos código ao serviço e ao arquivo de rotas. Esta API POST permitirá a criação de uma nova linguagem de programação popular. No método de serviço, obteremos o nome, o ano de lançamento e outras classificações do corpo da solicitação e os inseriremos na tabela linguagem_de_programação .

Abaixo está o código para o arquivo services/programmingLanguages.js :

 criação de função assíncrona (linguagem de programação) { const result=await db.query ( `INSERT INTO programming_languages (nome, release_year, githut_rank, pypl_rank, tiobe_rank) VALORES (?,?,?,?,?) `, [ programmingLanguage.name, programmingLanguage.released_year, programmingLanguage.githut_rank, programmingLanguage.pypl_rank, programmingLanguage.tiobe_rank ] ); let message='Erro ao criar linguagem de programação'; if (result.affectedRows) { mensagem='Linguagem de programação criada com sucesso'; } return {message};
} module.exports={ getMultiple, Criar
}

Para que a função acima seja acessível, precisamos adicionar uma rota para vinculá-la ao arquivo routes/prgrammingLanguages.js , da seguinte maneira:

/* linguagem de programação POST */
router.post ('/', função assíncrona (req, res, próximo) { tentar { res.json (espera programmingLanguages.create (req.body)); } catch (errar) { console.error (`Erro ao criar linguagem de programação`, err.message); próximo (errar); }
}); módulo.exportações=roteador;

Agora, também desenvolvemos uma maneira de adicionar novas linguagens de programação populares. Em seguida, adicionaremos um caminho para atualizar qualquer linguagem de programação existente.

PUT para atualizar uma linguagem de programação existente

Para atualizar uma linguagem de programação existente, usaremos o endpoint /programming-languages ​​/: id , de onde obteremos os dados para atualizar a linguagem. Para atualizar uma linguagem de programação, executaremos a consulta UPDATE com base nos dados que obtivemos na solicitação.

É benéfico entender que PUT é uma ação idempotente, o que significa que se a mesma chamada for feita repetidamente, ela produzirá exatamente os mesmos resultados. To enable updating existing records, we will add the following code to the programming language service:

async function update(id, programmingLanguage){ const result=await db.query( `UPDATE programming_languages SET name=?, released_year=?, githut_rank=?, pypl_rank=?, tiobe_rank=? WHERE id=?`, [ programmingLanguage.name, programmingLanguage.released_year, programmingLanguage.githut_rank, programmingLanguage.pypl_rank, programmingLanguage.tiobe_rank, id ] ); let message='Error in updating programming language'; if (result.affectedRows) { message='Programming language updated successfully'; } return {message};
} module.exports={ getMultiple, create, atualizar
}

Again, to wire up the code with the PUT endpoint, we will add the code as below to the programming languages route file just above module.exports=router;:

/* PUT programming language */
router.put('/:id', async function(req, res, next) { try { res.json(await programmingLanguages.update(req.params.id, req.body)); } catch (err) { console.error(`Error while updating programming language`, err.message); next(err); }
});

Now we have the ability to update any existing programming language — for instance, we can update a language’s name if we see a typo. Next, we will add the functionality to delete an existing programming language.

DELETE a programming language

At this juncture, we are able to create a new programming language and update one, too. Next, we will add some code to be able to delete an existing programming language. We will use the /programming-languages/:id path with the HTTP DELETE method.

Below is the code we’ll add to enable the delete functionality:

async function remove(id){ const result=await db.query( `DELETE FROM programming_languages WHERE id=?`, [id] ); let message='Error in deleting programming language'; if (result.affectedRows) { message='Programming language deleted successfully'; } return {message};
} module.exports={ getMultiple, create, update, retirar
}

Once again, to link up the service with the route, we will add the following code to the routes/programmingLanguages.js file:

/* DELETE programming language */
router.delete('/:id', async function(req, res, next) { try { res.json(await programmingLanguages.remove(req.params.id)); } catch (err) { console.error(`Error while deleting programming language`, err.message); next(err); }
});

As you have now built a great demo API, you might want to host it in one of the free Node.js hosting services.

Testing the APIs

After you have the Node.js Express server running with node index.js, you can test all the above API endpoints. To create a new programming language — let’s go with Dart — run the following curl command:

curl-i-X POST-H'Accept: application/json'\ -H'Content-type: application/json'http://localhost:3000/programming-languages \ --data'{"name":"dart","released_year": 2011,"githut_rank": 13,"pypl_rank": 20,"tiobe_rank": 25}'

This will result in the following output:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 55
ETag: W/"37-3mETlnRrtfrms6wlAjdgAXKq9GE"
Date: Mon, 01 Feb 2021 11:20:07 GMT
Connection: keep-alive {"message":"Programming language created successfully"}

You can remove the X-Powered-By header and add other security response headers by using Express.js Helmet. It will be a great addition to improve the API’s security.

For now, let’s look at the cURL to update the GitHut rank of Dart from 13 to 12:

curl-i-X PUT-H'Accept: application/json'\ -H'Content-type: application/json'http://localhost:3000/programming-languages/17 \ --data'{"name":"dart","released_year": 2011,"githut_rank": 12,"pypl_rank": 20,"tiobe_rank": 25}'

It will give an output like below:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 55
ETag: W/"37-0QPAQsRHsm23S9CNV3rPa+AFuXo"
Date: Mon, 01 Feb 2021 11:40:03 GMT
Connection: keep-alive {"message":"Programming language updated successfully"}

To test out the DELETE API, you can use the following cURL to delete Dart with ID 17:

curl-i-X DELETE-H'Accept: application/json'\ -H'Content-type: application/json'http://localhost:3000/programming-languages/17

It will result in the following output:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 55
ETag: W/"37-aMzd+8NpWQ09igvHbNLorsXxGFo"
Date: Mon, 01 Feb 2021 11:50:17 GMT
Connection: keep-alive {"message":"Programming language deleted successfully"}

If you are more used to a visual interface to do the testing for instance Postman you can import the cURL commands into Postman. Personally, I think cURL is used universally compared to Postman or any other GUI tool.

Further considerations

If this was a real-life API (not a demo one), I would strongly consider the following:

  1. Use a robust validation library like Joi to validate the input precisely, e.g., the name of the programming language is required and it doesn’t already exist in the database, etc.
  2. Add Helmet.js with Express.js to bump up the security depending on whether this is a public-facing or an internal API.
  3. It would be great to use a Node.js logging library like Winston to streamline the logs in a more manageable way.
  4. Following the Express.js production best practices will also be very beneficial.
  5. Last but not least, using Docker for the Node.js application would also be highly advisable.

Just a reminder that all the code is available as an open-source GitHub repository for your reference.

Conclusão

The above example REST API for popular programming languages serves as a good starting point. We now have a functioning API server with Node.js and MySQL. In this tutorial, we learned how to set up MySQL on a free service, and how to create an Express.js server that can handle various HTTP methods in connection to how it translates to SQL queries.

This should be a good foundation for you to build a real-world, production-ready REST API wherein you can practice the further considerations listed above. I hope you go on and build amazing REST APIs in the future.

The post Node.js, Express.js, and MySQL: A step-by-step REST API example appeared first on LogRocket Blog.

Source link