Como construir APIs REST rápidas com Node.js, MongoDB, Fastify e Swagger

Presumivelmente, nenhum desenvolvedor da Web é um estranho para as APIs REST e os desafios que a arquitetura de uma solução de API eficaz e eficiente traz.

Esses desafios incluem:

  • Velocidade (tempos de resposta da API)
  • Documentação (documentos claros e concisos, descrevendo a API)
  • Arquitetura e Sustentabilidade (base de código atualizável e expansível)

Neste tutorial vamos abordar todos os itens acima usando uma combinação de Node.js , MongoDB , Fastify e Swagger .

O código fonte do projeto está disponível no GitHub .

Antes de começarmos…

Você deve ter algum conhecimento de JavaScript iniciante / intermediário, ter ouvido falar do Node.js e do MongoDB e saber quais APIs REST são.

Abaixo estão alguns links para você se atualizar:

A tecnologia que vamos usar:

É uma boa ideia abrir as páginas acima em novas abas, para fácil referência.

Você precisará ter o seguinte instalado:

Você também precisará de um IDE e um terminal, eu uso o iTerm2 para Mac e o Hyper para Windows.

Vamos começar!

Inicialize um novo projeto abrindo seu terminal, executando cada uma das seguintes linhas de código:

 mkdir fastify-api 
 cd fastify-api 
 mkdir src 
 cd src 
 touch index.js 
 npm init

No código acima, criamos dois novos diretórios, navegamos neles, criamos um arquivo index.js e rubricamos nosso projeto via npm .

Você será solicitado a inserir vários valores ao inicializar um novo projeto, que você pode deixar em branco e atualizar em um estágio posterior.

Depois de concluído, um arquivo package.json é gerado no diretório src . Nesse arquivo, você pode alterar os valores inseridos quando o projeto foi inicializado.

Em seguida, instalamos todas as dependências que precisaremos:

 npm eu nodemon mangusto fastify fastify-swagger boom

Abaixo está uma breve descrição do que cada pacote faz, citado em seus respectivos sites:

nodemon

O nodemon é uma ferramenta que ajuda a desenvolver aplicativos baseados em node.js reiniciando automaticamente o aplicativo do nó quando as alterações de arquivo no diretório são detectadas.

não nodemon não necessita de quaisquer alterações adicionais ao seu código ou método de desenvolvimento. O nodemon é um wrapper de substituição para o node , para usar o nodemon substitua o node da palavra na linha de comando ao executar seu script.

Para configurar o nodemon , precisamos adicionar a seguinte linha de código ao nosso arquivo package.json , no objeto scripts:

 "Start": "./node_modules/nodemon/bin/nodemon.js ./src/index.js",

Nosso arquivo package.json deve ter a seguinte aparência:

package.json

mangusto

O Mongoose fornece uma solução direta e baseada em esquema para modelar os dados do seu aplicativo. Ele inclui conversão de tipo incorporada, validação, criação de consulta, ganchos de lógica de negócios e muito mais, fora da caixa.

fastify

O Fastify é um framework web altamente focado em fornecer a melhor experiência de desenvolvedor com o mínimo de overhead e uma poderosa arquitetura de plugins. É inspirado por Hapi e Express e, tanto quanto sabemos, é um dos quadros web mais rápidos da cidade.

fastify-swagger

Gerador de documentação do Swagger para o Fastify. Ele usa os esquemas que você declara em suas rotas para gerar um documento complacente.

estrondo

lança fornece um conjunto de utilitários para retornar erros HTTP.

Configure o servidor e crie a primeira rota!

Adicione o seguinte código ao seu arquivo index.js :

index.js

Nós exigimos o framework Fastify , declaramos nossa primeira rota e inicializamos o servidor na port 3000 , o código é bastante auto-explicativo, mas tome nota do objeto options passado ao inicializar o Fastify :

 // Exigir o framework fastify e instanciá-lo 
 const fastify = require ('fastify') ({ 
 logger: true 
 })

O código acima ativa o criador de logs integrado do Fastify, que é desativado por padrão.

Agora você pode executar o código a seguir em seu diretório src em seu terminal :

 npm start

Agora quando você navega para http: // localhost: 3000 / você deve ver o objeto {hello:world} retornado.

Nós voltaremos ao arquivo index.js mas por enquanto vamos continuar a configuração do nosso banco de dados.

Inicie o MongoDB e crie o modelo!

Uma vez que o MongoDB tenha sido instalado com sucesso, você pode abrir uma nova janela de terminal e iniciar uma instância do MongoDB executando o seguinte:

 mongod

Com o MongoDB , não precisamos criar um banco de dados. Podemos apenas especificar um nome na configuração e, assim que armazenarmos os dados, o MongoDB criará esse banco de dados para nós.

Adicione o seguinte ao seu arquivo index.js :

 ...
 // Requer módulos externos 
 const mongoose = require ('mangusto')
 // Conecte-se ao DB 
 mongoose.connect ('mongodb: // localhost / mycargarage') 
 .then (() => console.log ('MongoDB connected…')) 
 .catch (err => console.log (err))
 ...

No código acima, exigimos o Mongoose e nos conectamos ao nosso banco de dados MongoDB . O banco de dados é chamado mycargarage e, se tudo mycargarage bem, você verá o MongoDB connected... em seu terminal.

Observe que você não precisou reiniciar o aplicativo, graças ao pacote Nodemon que adicionamos anteriormente.

Agora que nosso banco de dados está funcionando, podemos criar nosso primeiro modelo. Crie uma nova pasta dentro do diretório src chamado models , e dentro dela crie um novo arquivo chamado Car.js e adicione o seguinte código:

O código acima declara nosso carSchema que contém todas as informações relacionadas aos nossos carros. Além dos dois tipos de dados óbvios: String e Number . Também fazemos uso de um Map que é relativamente novo no Mongoose e você pode ler mais sobre isso aqui . Em seguida, exportamos nosso carSchema para ser usado em nosso aplicativo.

Poderíamos prosseguir com a configuração de nossas rotas, controladores e config no arquivo index.js , mas parte deste tutorial é demonstrar uma base de código sustentável. Portanto, cada componente terá sua própria pasta.

Crie o controlador do carro

Para começar a criar os controladores, criamos uma pasta no diretório src chamada controllers e, dentro da pasta, criamos um arquivo carController.js :

carController.js

O acima pode parecer um pouco demais para absorver, mas na verdade é realmente simples.

  • Nós exigimos que o boom lide com nossos erros: boom.boomify(err) .
  • Exportamos cada uma das nossas funções que usaremos em nossa rota.
  • Cada função é uma função assíncrona que pode conter uma expressão aguardam que interrompe a execução da função assíncrona e aguarda a resolução da Promise passou, e, em seguida, retoma a execução da função assíncrona e retorna o valor resolvido. Aprenda mais aqui.
  • Cada função é envolvida em uma instrução try / catch. Aprenda mais aqui.
  • Cada função usa dois parâmetros: req (o pedido) e reply (a resposta). Em nosso tutorial, usamos apenas o parâmetro request. Vamos usá-lo para acessar o corpo da solicitação e os parâmetros da solicitação, o que nos permite processar os dados. Aprenda mais aqui.
  • Anote o código na linha 31:
    const car = new Car({ …req.body })
    Isso faz uso do operador de propagação de JavaScript . Aprenda mais aqui.
  • Tome nota do código na linha 42:
    const { …updateData } = car
    Isso faz uso da desestruturação do JavaScript em conjunto com o operador de propagação. Aprenda mais aqui.

Além disso, utilizamos alguns recursos padrão do Mongoose usados para manipular nosso banco de dados.

Provavelmente você está queimando para ativar sua API e fazer uma verificação de integridade, mas antes de fazer isso, precisamos apenas conectar o controlador às rotas e, por último, conectar as rotas ao aplicativo.

Crie e importe as rotas

Mais uma vez, podemos começar criando uma pasta no diretório raiz do nosso projeto, mas desta vez, ela é chamada de routes . Dentro da pasta, criamos um arquivo index.js com o seguinte código:

index.js

Aqui estamos exigindo nosso controlador e atribuindo cada uma das funções que criamos em nosso controlador para nossas rotas.

Como você pode ver, cada rota consiste em um método, uma URL e um manipulador, instruindo o aplicativo sobre qual função usar quando uma das rotas é acessada.

O :id seguindo algumas das rotas é uma maneira comum de passar parâmetros para as rotas, e isso nos permitirá acessar o id da seguinte forma:

http://127.0.0.1:3000/api/cars/5bfe30b46fe410e1cfff2323

Juntando tudo e testando nossa API

Agora que temos a maioria de nossas peças construídas, precisamos conectá-las para começar a veicular dados por meio de nossa API . Primeiramente, precisamos importar nossas rotas que criamos adicionando a seguinte linha de código ao nosso arquivo index.js principal:

 rotas const = require ('./ routes')

Em seguida, precisamos percorrer nossa matriz de rotas para inicializá-los com o Fastify. Podemos fazer isso com o seguinte código, que também precisa ser adicionado ao arquivo principal do index.js :

 routes.forEach ((rota, índice) => { 
 fastify.route (rota) 
 })

Agora estamos prontos para começar a testar!

A melhor ferramenta para o trabalho é o Postman , que usaremos para testar todas as nossas rotas. Enviaremos nossos dados como objetos brutos no corpo da solicitação e como parâmetros.

Encontrando todos os carros:

Encontrar um único carro:

Adicionando um carro novo **:

** Os serviços parecem estar vazios, mas as informações de fato persistem no banco de dados.

Atualizando um carro:

Excluindo um carro:

Agora temos uma API totalmente funcional – mas e a documentação? É aqui que o Swagger é realmente útil.

Adicionando Swagger e finalizando.

Agora vamos criar nossa pasta final chamada config. Dentro vamos criar um arquivo chamado swagger.js com o seguinte código:

O código acima é um objeto com as opções que passaremos para o nosso plugin fastify-swagger . Para fazer isso, precisamos adicionar o seguinte ao nosso arquivo index.js :

 // Importar opções de swagger 
 const swagger = require ('./ config / swagger')
 // Registre o Swagger 
 fastify.register (require ('fastify-swagger'), swagger.options)

E então precisamos adicionar a seguinte linha após termos inicializado nosso servidor Fastify :

 ... 
 espere fastify.listen (3000) 
 fastify.swagger () 
 fastify.log.info (`ouvindo em $ {fastify.server.address (). port}`) 
 ...

E é isso! Se você agora navegar para http: // localhost: 3000 / documentation , deverá ver o seguinte:

Tão simples como isso! Agora você tem uma documentação de atualização automática da API que evoluirá com sua API. Você pode facilmente adicionar informações adicionais às suas rotas, veja mais aqui .

Qual é o próximo?

Agora que temos uma API básica, as possibilidades são ilimitadas. Pode ser usado como base para qualquer aplicativo imaginável.

No próximo tutorial, vamos integrar o GraphQL e eventualmente integrar o frontend com o Vue.js também!