Skip to main content

Plugins do Fastify como blocos de construção de uma API backend em Node.js

Escrito por
blog feature snyk container custom base recommendations

28 de maio de 2024

0 minutos de leitura

No desenvolvimento de APIs backend em Node.js, o Fastify se destaca pelo ecossistema de plugins e pela arquitetura, oferecendo uma alternativa atraente ao framework Express tradicional. Esse framework web altamente eficiente e com baixo overhead se diferencia pela velocidade impressionante e pela simplicidade. No centro do design do Fastify está uma arquitetura robusta de plugins que aproveita ao máximo os recursos assíncronos do Node.js e estabelece um novo padrão de desempenho entre os frameworks Node.js, com os plugins do Fastify em papel fundamental.

O desenvolvimento do Fastify é impulsionado por uma comunidade open source em expansão, que mantém o framework relevante e atualizado com as últimas tendências de desenvolvimento de aplicações web. Para quem trabalha com desenvolvimento web backend em 2024, o Fastify provou ser um framework valioso para criar aplicações web rápidas, escaláveis e seguras.

Por que o Fastify e seus plugins são a base de uma API backend robusta em Node.js

Para desenvolver aplicações web modernas, o Fastify se tornou uma opção atraente entre desenvolvedores. Criado para o Node.js, esse framework web combina desempenho, flexibilidade e recursos que facilitam o trabalho de quem desenvolve. Nesta seção, vamos explorar as vantagens de usar o Fastify no desenvolvimento de aplicações modernas.

Suporte moderno a ESM

O Fastify oferece suporte nativo a módulos ECMAScript (ESM). Isso é importante porque ESM é o formato oficial dos módulos JavaScript de pacotes. Com o Fastify, você pode usar a sintaxe import e export nativamente, sem precisar de uma etapa de transpilação.

Veja um exemplo simples de servidor Fastify usando ESM:

import fastify from 'fastify';

const server = fastify();

server.get('/', async (request, reply) => {
  return { hello: 'world' }
});

server.listen({port: 3000}, (err, address) => {
  if (err) throw err
  server.log.info(`Server listening at ${address}`)
});

Definição de rotas adequada com promises e async/await

O Fastify facilita o tratamento de rotas com a sintaxe async/await. O resultado é um código mais claro e legível em comparação com os padrões tradicionais de callback.

O Express não oferece suporte nativo a async/await nas definições de rotas, o que muitas vezes leva ao callback hell ou à necessidade de envolver os handlers de rota em blocos try/catch para tratar erros. Com o suporte nativo do Fastify a async/await, fica mais fácil escrever e manter código assíncrono usando promises.

Veja um exemplo de como o Fastify usa async/await na definição de uma rota:

server.get('/api/tasks', async (request, reply) => {
  const tasks = await Tasks.findAll();
  return tasks;
});

Alto desempenho com resolução rápida de rotas por árvore radix

O Fastify foi projetado para oferecer alto desempenho. Ele conta com uma resolução rápida de rotas por árvore radix, um algoritmo de roteamento altamente eficiente. Assim, o Fastify pode lidar com muitas rotas com overhead mínimo e responder rapidamente, mesmo sob carga intensa.

Uma arquitetura rica de plugins Fastify com encapsulamento

O Fastify tem uma arquitetura rica de plugins que oferece suporte a encapsulamento. Isso permite dividir facilmente a aplicação em componentes isolados, cada um com seu próprio conjunto de rotas, plugins e decorators. Essa abordagem organiza melhor o código e reduz o risco de conflitos de nomes.

Veja um exemplo de plugin Fastify que adiciona uma função utilitária ao handler da rota:

import fp from 'fastify-plugin';

export default fp(async function (fastify, opts) {
  fastify.decorate('utility', () => 'This is a utility function');
});

Use este plugin da seguinte forma:

// import and get a fastify server instance,
// and then:
server.register(import('./utility-plugin.js'));

server.get('/', async (request, reply) => {
  return server.utility();
});

Injeção de dependências leve

O sistema de plugins do Fastify também funciona como um sistema leve de injeção de dependências (DI). Isso facilita o compartilhamento de utilitários e serviços comuns por toda a aplicação, sem recorrer a singletons ou variáveis globais.

No exemplo a seguir, uma conexão com o banco de dados é compartilhada por diferentes partes da aplicação:

fastify.register(async function (fastify, opts) {
  const db = await someDbConnectionLibrary(opts.connectionString);

  fastify.decorate('db', db);
});

Uma API backend simples em Node.js com Fastify

Este artigo apresenta os blocos fundamentais para criar APIs backend em Node.js com Fastify e seus plugins recomendados em 2024. Vamos nos aprofundar nos componentes essenciais de uma aplicação Fastify, do roteamento e middleware à validação e serialização.

Além disso, dada a importância da cibersegurança no mundo digital de hoje, vamos abordar brevemente aspectos de segurança web e como usar plugins do Fastify para tratá-los — um ponto crucial muitas vezes ignorado na pressa de desenvolver uma aplicação.

Para começar, verifique se você tem a versão LTS mais recente do Node.js instalada no sistema (na data de publicação deste artigo, é a v20.11.1). Em seguida, inicialize um novo projeto Node.js e instale o Fastify com npm, como mostrado abaixo:

$ mkdir fastify-app && cd fastify-app
$ npm init -y
$ npm install --save fastify

Edite o arquivo package.json e adicione a definição da chave type: module no nível superior para habilitar o suporte a ESM:

{
  "type": "module",
}

Em seguida, podemos criar a estrutura básica de uma aplicação Fastify em um arquivo server.js no diretório raiz do projeto:

// Import Fastify using ESM syntax
import Fastify from "fastify";

const fastify = Fastify({ logger: true });

// Defining a route
fastify.get("/", async (request, reply) => {
  return { hello: "world" };
});

async function startServer() {
  try {
    // Start the server
    const address = await fastify.listen({
      port: 3000,
      host: "localhost",
    });

    // Log the server start information using the address returned by Fastify
    // Fastify will already log the server start information by default
    // But here is an example of how you can log the server start information
    // fastify.log.info(`Server starting up at ${address}`);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
}

startServer();

Encapsulando a rota da API em um plugin Fastify

O Fastify incentiva o uso de plugins para organizar o código e permitir o encapsulamento. Assim, você pode agrupar códigos relacionados e evitar conflitos entre diferentes partes da aplicação.

Vamos refatorar nossa rota "Hello World" em um plugin Fastify:

const fastify = require('fastify')({ logger: true });

const helloRoute = async (fastify, options) => {
  fastify.get('/', async (request, reply) => {
    return { hello: 'world' };
  });
};

fastify.register(helloRoute);

const start = async () => {
  try {
    await fastify.listen(3000);
    fastify.log.info(`server listening on ${fastify.server.address().port}`);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};
start();

Usando schemas de requisição e resposta de rotas

O Fastify permite validar as requisições recebidas e estruturar as respostas enviadas usando JSON Schema. Isso ajuda a garantir a integridade dos dados da aplicação e simplifica a criação da documentação.

Veja como definir um schema de requisição e resposta para a rota "Hello World":

const helloRoute = async (fastify, options) => {
  fastify.route({
    method: 'GET',
    url: '/',
    schema: {
      response: {
        200: {
          type: 'object',
          properties: {
            hello: { type: 'string' },
          },
        },
      },
    },
    handler: async (request, reply) => {
      return { hello: 'world' };
    },
  });
};

fastify.register(helloRoute);

Agora, o Fastify vai validar automaticamente a resposta da rota "Hello World" com base no schema fornecido. Isso ajuda a detectar possíveis bugs e garante que a aplicação se comporte como esperado.

Plugins Fastify como blocos de construção de aplicações Fastify

Nesta seção, vamos conhecer quatro plugins importantes do Fastify: @fastify/pino, @fastify/cors, @fastify/env e @fastify/swagger, além de @fastify/swagger-ui. Ao criar uma API backend em Node.js, esses plugins ajudam a formar a base de qualquer aplicação Fastify.

O logger Pino para Fastify

Pino é um logger de desempenho excepcional para Node.js, com plugins próprios que ampliam sua integração com outros sistemas de logging, como o Sentry.

Você pode aproveitar o fato de que o Fastify usa o Pino como logger padrão. Ao inicializar o Fastify com { logger: true }, você já está usando o Pino nos bastidores. Mas, se quiser mais controle sobre o nível de logging ou outras configurações específicas do Pino, pode passar um objeto de configuração à propriedade logger.

Durante o desenvolvimento, talvez você prefira logs mais fáceis de ler e com mais cores. Para isso, podemos usar o pacote pino-pretty. Primeiro, instale pino e pino-pretty:

npm install --save pino pino-pretty

Em seguida, configure o pino-pretty assim:

import pino from "pino";

const logger = pino({
  transport: {
    target: "pino-pretty",
    options: {
      colorize: true,
    },
  },
});

logger.info("Hello from pino-pretty");

const fastify = Fastify({
  logger: logger,
});

No exemplo acima, inicializamos um logger com pino e o configuramos para usar pino-pretty como destino de transporte, com a opção colorize para habilitar logs coloridos. Depois, passamos nossa variável personalizada logger para a opção logger do Fastify.

Isso transforma os logs em um formato mais fácil de ler e entender:

[12:13:43.499] INFO (95477): hello from pino-pretty
[12:13:43.517] INFO (95477): Server listening at http://[::1]:3000
[12:13:43.518] INFO (95477): Server listening at http://127.0.0.1:3000

Entre as vantagens de usar Pino no Fastify estão:

  • Logging mais rápido: o principal objetivo do Pino é ser o logger mais rápido para Node.js.

  • Logger versátil: oferece suporte a diferentes níveis de log e pode formatar logs como JSON.

O plugin Fastify @fastify/cors

O plugin @fastify/cors oferece uma forma simples de usar CORS (compartilhamento de recursos entre origens) na sua aplicação Fastify.

Vantagens:

  • Segurança: ajuda a gerenciar o fluxo de dados entre diferentes origens.

  • Personalização: permite definir uma função personalizada para configurar as opções de CORS.

Veja um exemplo simples de como adicionar e usar o plugin @fastify/cors:

// after creating the fastify instance
// let's register the fastify cors plugin:
fastify.register(require('@fastify/cors'), { 
  origin: '*',
  methods: ['GET','POST', 'PUT', 'DELETE']
})

Depois, podemos testar se a configuração do CORS está funcionando fazendo uma requisição cURL ao servidor Fastify:

curl -i http://localhost:3000

A resposta deve incluir o cabeçalho Access-Control-Allow-Origin, indicando que a configuração do CORS está funcionando como esperado:

HTTP/1.1 200 OK
access-control-allow-origin: *
content-type: application/json; charset=utf-8
content-length: 17
Date: Sun, 18 Feb 2024 10:20:15 GMT
Connection: keep-alive
Keep-Alive: timeout=72

O plugin Fastify @fastify/env

É comum que desenvolvedores Node.js usem variáveis de ambiente para configurar aplicações — e, mais ainda, que recorram ao arquivo .env para gerenciá-las.

É aí que o plugin Fastify @fastify/env é útil. Você pode usar dotenv ou o --env-file integrado ao Node.js para carregar a configuração, mas este plugin permite acessar as variáveis de ambiente diretamente na aplicação Fastify, além de validar a configuração e converter tipos.

Veja um exemplo simples de como adicionar e usar o plugin @fastify/env. Comece instalando o plugin e criando um arquivo .env simples:

npm install --save @fastify/env
echo "PORT=3001" > .env

Em seguida, atualize o código de server.js para registrar o novo plugin Fastify:

fastify.register(import('@fastify/env'), {
  dotenv: true,
  schema: {
    type: 'object',
    required: [ 'PORT' ],
    properties: {
      PORT: {
        type: 'string',
        default: 3000
      }
    }
  }
})

Ao registrar o plugin Fastify @fastify/env, você acessa a configuração definida no arquivo .env pelo objeto fastify.config. Mas não podemos simplesmente usá-lo diretamente. Precisamos introduzir um novo conceito relacionado à arquitetura de plugins do Fastify.

Como a arquitetura de plugins do Fastify é assíncrona, é necessário aguardar a inicialização de todos os plugins antes que eles sejam aplicados. Isso garante que estejam registrados corretamente e prontos para uso. Se você pular essa etapa, vai receber um erro ao tentar acessar o objeto fastify.config.

Portanto, precisamos atualizar nossa nova função startServer() da seguinte forma:

try {
    // wait for all plugins to run 
    await fastify.ready();
    // Start the server
    const address = await fastify.listen({
      // now we can access the fastify.config.PORT configuration
      port: fastify.config.PORT,
      host: "localhost",
    });

Vantagens de usar o plugin @fastify/env:

  • Validação de variáveis de ambiente: garante que as variáveis obrigatórias estejam definidas.

  • Conversão de tipos: converte as variáveis de ambiente para os tipos necessários.

  • Injeção de dependências leve: facilita o compartilhamento da configuração por toda a aplicação onde quer que você tenha acesso à instância da aplicação fastify.

Documente APIs backend em Node.js com os plugins Fastify @fastify/swagger e @fastify/swagger-ui

O plugin @fastify/swagger ajuda a gerar e disponibilizar uma página de documentação Swagger para sua aplicação Fastify. O @fastify/swagger-ui oferece uma interface integrada para essa documentação, acessível pelo navegador. A própria aplicação Fastify disponibiliza a página do Swagger UI.

Como antes, vamos começar adicionando esses plugins à aplicação Fastify:

npm install --save @fastify/swagger @fastify/swagger-ui

Em seguida, registramos os dois plugins no arquivo server.js:

fastify.register(import('@fastify/swagger'), {
  routePrefix: '/documentation',
  swagger: {
    info: {
      title: 'Test swagger',
      description: 'testing the fastify swagger api',
      version: '0.1.0'
    },
    host: 'localhost',
    schemes: ['http'],
    consumes: ['application/json'],
    produces: ['application/json']
  },
  exposeRoute: true
})

fastify.register(import('@fastify/swagger-ui'))

Reinicie o servidor Fastify e acesse http://localhost:3001/documentation no navegador para ver a página de documentação Swagger UI gerada. Pronto: você tem uma página de documentação Swagger totalmente funcional para sua aplicação Fastify.

O plugin Fastify @fastify/swagger adiciona documentação Swagger para APIs de back-end em Node.js.

Uma observação sobre segurança: em um ambiente de produção, considere proteger a página de documentação Swagger UI com autenticação e autorização. Evite também usar seus servidores Node.js de produção para disponibilizá-la.

Vantagens:

  • Documentação fácil de APIs: gera documentação de API automaticamente.

  • Personalização: permite personalizar a página de documentação.

Juntando tudo

Como vimos, o ecossistema ativo do Fastify oferece diversos plugins que podem aprimorar bastante o desenvolvimento de APIs backend em Node.js. De recursos de logging melhores com pino e pino-pretty à segurança do navegador com CORS por meio de @fastify/cors, passando pelo gerenciamento de variáveis de ambiente com @fastify/env e pela documentação da API com @fastify/swagger e @fastify/swagger-ui, essas ferramentas simplificam o fluxo de trabalho, melhoram o desempenho e elevam a qualidade das aplicações.

Em resumo, aprendemos que os plugins Fastify permitem:

Adotar o desenvolvimento modular: a arquitetura de plugins do Fastify promove o desenvolvimento modular e incentiva uma base de código organizada e fácil de manter. Ao integrar esses plugins, desenvolvedores podem se concentrar na lógica de negócios em vez de escrever código repetitivo, acelerando o desenvolvimento sem comprometer o desempenho ou a escalabilidade.

Aumente a produtividade e o desempenho: cada plugin, com seu foco específico, ajuda a resolver desafios comuns do desenvolvimento web, permitindo que você crie APIs robustas, eficientes e seguras. A integração simples com o Fastify e os benefícios oferecidos, como logs aprimorados, compartilhamento de recursos entre origens, configuração do ambiente e documentação da API, contribuem diretamente para aumentar a produtividade dos desenvolvedores e o desempenho das aplicações.

Explore ainda mais: embora tenhamos destacado alguns plugins essenciais, o ecossistema do Fastify oferece muitos outros para atender a diferentes necessidades, da autenticação à integração com bancos de dados, passando pelo controle de taxa de requisições e muito mais. Recomendamos que você explore a página de plugins do Fastify e experimente essas ferramentas para descobrir como elas podem otimizar e aprimorar ainda mais o desenvolvimento das suas APIs.

Você pode consultar o código-fonte completo de todos os exemplos acima de uma API backend em Node.js com os plugins do Fastify que abordamos.

Leia mais

blog feature ai lilac
Blog

Transforme seu backlog de vulnerabilidades em pull requests com remediação agentiva

O Evo Remediation Agent está em Open Preview e traz a resolução automatizada de dependências para o Evo Agentic AppSec. Agora, as equipes de AppSec podem executar campanhas contínuas de remediação

AI Background min crop
Blog

A IA está acionando todos os riscos que você aceitou: sete insights do painel de segurança de IA sem filtros

A IA está tornando os ataques mais baratos e rápidos, expondo riscos que as organizações já carregam. Quatro líderes de segurança explicam por que a defesa na velocidade das máquinas e a correção mais rápida são essenciais.

blog feature ai violet
Blog

VulnBump: agentes de IA conseguem corrigir dependências vulneráveis sem quebrar o build?

O VulnBump testa agentes de IA em 307 atualizações reais de dependências. Uma correção só é considerada válida se eliminar a vulnerabilidade e mantiver o build e os testes passando.