Voltar

Técnicas do NestJS para aplicativos backdrop

/ 9 min read

5 Técnicas do NestJS para aplicativos

NestJS é uma estrutura poderosa e altamente evolutiva, embora complexa. Com muitos recursos prontos para uso, é uma excelente escolha para desenvolvedores que desejam criar aplicativos escaláveis e robustos. No entanto, alguns de seus recursos menos conhecidos e subutilizados são verdadeiras joias escondidas. Neste artigo, apresentarei cinco dessas joias, que podem ser extremamente úteis em contextos específicos.

Controle de versão

O controle de versão é um aspecto essencial do desenvolvimento de APIs da Web, permitindo que diferentes versões da API coexistam e sejam acessíveis de forma independente. Antes do lançamento do NestJS 8, não havia suporte pronto para uso para o controle de versão de APIs, o que significava que os desenvolvedores precisavam implementá-lo manualmente.

Felizmente, o NestJS 8 introduziu suporte para três tipos diferentes de controle de versão de API: controle de versão de URI, versionamento de cabeçalho e controle de versão do tipo de mídia. O controle de versão de URI é o padrão e envolve a inclusão da versão na URI da solicitação.

Para habilitar o controle de versão de URI, basta seguir os seguintes passos:

app.enableVersioning({
type: VersioningType.URI,
});

Para aplicar o controle de versão de URL ao controlador:

@Controller({
version: '1',
})
export class BMWControllerV1 { ... }

Ou você pode aplicá-lo a rotas individuais

@Version('2')
@Get('bmw')
findAllV2(): string {
return 'This action returns all bmw for version 2';
}

Outro recurso útil é o chamado “Versionamento Neutro”, que permite definir um controlador como neutro em termos de versão. Com essa abordagem, um único controlador pode lidar com várias versões da API, simplificando assim a manutenção e evolução da aplicação.

@Controller({
version: VERSION_NEUTRAL,
})
export class BMWController { ... }

Uma das vantagens do novo recurso de versionamento no NestJS é a sua simplicidade e flexibilidade. Por exemplo, se uma solicitação de entrada não contiver uma versão, ela será automaticamente mapeada para o controlador com a versão neutra VERSION_NEUTRAL. Isso torna a implementação e a manutenção de APIs mais intuitivas e eficientes.

Em resumo, essa é apenas mais uma das muitas boas razões para escolher o NestJS como estrutura para desenvolvimento de aplicativos.

Usar cache na memória com um decorador personalizado

Uau! Você sabia que o gerenciamento de cache pode ser um dos maiores desafios em Ciência da Computação? Mas não se preocupe, o NestJS torna tudo mais fácil com um gerenciador de cache pronto para uso que vem com um armazenamento de dados na memória padrão.

E o melhor de tudo? O uso dessa ferramenta é simples e descomplicado. Tudo o que você precisa fazer é importar o módulo de cache CacheModule e configurar as opções de cache para a sua aplicação. Com essa funcionalidade integrada, você pode melhorar significativamente o desempenho da sua API e aliviar a carga do servidor.

Não é incrível? O NestJS realmente pensou em tudo para tornar a sua experiência de desenvolvimento mais fácil e eficiente.

imports: [CacheModule.register()]

Em seguida, podemos injetá-lo em uma class usando o token e começar a usá-lo.CACHE_MANAGER

constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
// Para recuperar itens do cache
await this.cacheManager.get('key');
// Para adicionar um item ao cache
await this.cacheManager.set('key', 'value');

Para implementar o cache na API NestJS, o código geralmente é como o seguinte.

const value = await this.cacheManager.get('test-key-bmw');
if (!value) {
const response = await this.getHello();
this.cacheManager.set(
'test-key-bmw',
response,
{ ttl: 0 },
);
return response;
}
return value;

Quando o seu aplicativo começa a crescer, é comum que o código comece a se repetir em diversos lugares, o que pode tornar o desenvolvimento e a manutenção cada vez mais difíceis.

Mas como podemos evitar essa duplicação de código? A resposta é um decorador personalizado!

O decorador é uma função que pode estender o comportamento de outra função sem modificá-la diretamente. No caso do gerenciador de cache, para criar um decorador personalizado, precisamos injetar o gerenciador de cache na função.

Felizmente, graças ao poderoso NestJS DI, a criação de um decorador personalizado é relativamente simples. Abaixo está um exemplo de implementação de um decorador personalizado que utiliza o gerenciador de cache na memória.

Com essa funcionalidade, você pode criar um gerenciamento de cache mais eficiente e organizado, evitando a repetição de código e tornando a manutenção da sua aplicação muito mais fácil.

import { CACHE_MANAGER, Inject } from '@nestjs/common';
export const cacheManagerDecorator = (ttl = 10) => {
const injectCache = Inject(CACHE_MANAGER);
return function (
target: any,
_propertyName: string,
descriptor: PropertyDescriptor,
) {
injectCache(target, 'cache');
const decoratedMethod = descriptor.value;
const cacheKey = `${target.constructor.name}-${decoratedMethod?.name}`;
descriptor.value = async function () {
const cachedData = await this.cache.get(cacheKey);
if (cachedData) {
console.log('cachedData:', cachedData);
return cachedData;
}
const response = await decoratedMethod.apply(this, arguments);
this.cache.set(cacheKey, response, { ttl: ttl });
console.log('response:', response);
return response;
};
};
};

Para entender melhor a implementação do decorador personalizado para o gerenciador de cache no NestJS, é importante compreender a essência da solução.

O target é a classe que contém o decorador, enquanto o descriptor é a referência ao método da classe que está sendo decorado. Na linha 12, por exemplo, extraímos o nome do construtor de destino e o nome do método para formar um ‘cacheKey’ exclusivo.

O ttl representa a duração para invalidar o cache e, por padrão, é definido como 10 segundos.

Vale lembrar que, nas linhas 4 e 10 do código, o uso do decorador @Inject no construtor é equivalente.

Essa solução permite que você tenha um gerenciamento de cache mais eficiente e organizado, evitando repetição de código e simplificando a manutenção da sua aplicação. Com o poder do NestJS, é possível criar soluções robustas e escaláveis em pouco tempo e com um mínimo de esforço.

constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

O uso do decorador é tão simples quanto:

@cacheManagerDecorator()
async getHello() {
return `Hello - ${new Date().toLocaleString()}`;
}

É muito mais limpo agora, e podemos aplicá-lo a qualquer serviço que precise ser armazenado em cache.

Trabalho NestJS Cron

Embora o NestJS seja projetado principalmente para a API REST, ele também vem com um pacote de agendamento. O pacote expõe uma API que nos permite criar trabalhos cron.

Para começar com o trabalho cron do NestJS, precisamos instalar o pacote primeiro

Terminal window
npm install --save @nestjs/schedule
npm install --save-dev @types/cron

Você pode criar um trabalho cron de duas maneiras diferentes:

criar o trabalho cron de forma declarativa. O decorador suporta o padrão cron.@Cron

@Cron('45 * * * * *')
handleCron() {
this.logger.debug('Called when the current second is 45');
}

O método será chamado a cada minuto, no 45º segundo. Você também pode usar a expressão cron predefinida para configurar o trabalho.handleCron

@Cron(CronExpression.EVERY_MINUTE)

crie dinamicamente um novo trabalho cron. Usando o objeto do pacote, você pode criar o trabalho cron. Em seguida, você pode usar o método para adicionar o trabalho ao registro de CronJobcronSchedulerRegistry.addCronJob()

addCronJob(name: string, seconds: string) {
const job = new CronJob(`${seconds} * * * * *`, () => {
this.logger.warn(`time (${seconds}) for job ${name} to run!`);
});
this.schedulerRegistry.addCronJob(name, job);
job.start();

Para descobrir outras opções e recursos disponíveis no pacote de agendamento de tarefas do NestJS, confira a documentação oficial.

Validar entrada com pipes

A validação de dados é essencial em qualquer API da web. No NestJS, podemos usar pipes para executar a validação em tempo de execução. Quando um pipe é usado para validação, os dados serão retornados inalterados se a validação for bem-sucedida, caso contrário, um erro será lançado se os dados estiverem incorretos.

O NestJS possui pipes prontos para uso integrados, incluindo o ValidationPipe. O ValidationPipe interno é baseado no popular pacote de validação de classe. Veja um exemplo de uso abaixo:

import { IsString, IsInt } from 'class-validator';
export class CreateBMWDto {
@IsString()
name: string;
@Length(10)
description: string;
}

@IsString(): verifica se um valor de entrada é uma string. @Length(10): verifica se o valor tem um comprimento mínimo de 10 caracteres. Ele também retornará um erro se o valor não for uma string.

Quando uma solicitação é recebida com uma propriedade inválida no corpo da solicitação, o aplicativo responderá automaticamente com um status de resposta 400 Bad Request.

No exemplo acima, a validação é aplicada com decoradores. O mesmo decorador pode ser usado em diferentes classes DTO em todo o aplicativo NestJS, facilitando a manutenção da lógica de validação.

Há muitos outros decoradores disponíveis no tubo de validação embutido. Você também pode criar seu próprio tubo de validação personalizado usando os pacotes class-transformer e class-validator.

Os tubos no NestJS são flexíveis e poderosos. Eles podem ser síncronos e assíncronos e podem ser aplicados em diferentes níveis de escopo: parâmetro, método, controlador ou global.

Para obter mais detalhes sobre como usar os pipes NestJS para validação, você pode conferir a documentação oficial.

Melhore o desempenho alternando a plataforma subjacente

Por padrão, o NestJS é executado em cima do Express. Comparado a outras estruturas de API, seu desempenho pode não ser o melhor. Para a maioria dos aplicativos, a diferença de desempenho não será notável.

No entanto, se você estiver trabalhando em um aplicativo onde o desempenho rápido é uma prioridade, pode ser vantajoso migrar seu aplicativo NestJS para o Fastify. O Fastify é aproximadamente duas vezes mais rápido que o Express.

Felizmente, a migração do Express para o Fastify é relativamente simples, graças à independência da estrutura fornecida pelo NestJS por meio de padrões de adaptador. Em outras palavras, o design do NestJS torna o Express e o Fastify intercambiáveis.

Para usar o Fastify, basta instalar o pacote

Terminal window
yarn add @nestjs/platform-fastify

e configurar o aplicativo para usá-lo. A documentação oficial do NestJS fornece detalhes sobre como migrar para o Fastify e aproveitar ao máximo sua velocidade aprimorada. Em seguida, podemos configurar a plataforma Fastify em main.ts.

async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter()
);
await app.listen(3000);
}

Agora que o Fastify foi instalado, podemos usá-lo como o provedor HTTP no NestJS. É importante notar que, como o Fastify é uma estrutura diferente do Express, os pacotes que dependem do Express precisarão ser substituídos por pacotes equivalentes do Fastify. É possível encontrar muitos pacotes de middleware do Fastify disponíveis na web. Alguns pacotes comuns usados no NestJS são o fastify-cors e o fastify-helmet. No entanto, é importante ler a documentação de cada pacote cuidadosamente antes de usá-lo, para garantir que seja compatível com o NestJS e o Fastify.