blog do lê

Criando uma API REST com NestJS: Do zero ao primeiro endpoint

Neste guia, você aprenderá como iniciar um projeto NestJS, instalar o Nest CLI, estruturar seu projeto, e criar o seu primeiro endpoint

E aí, pessoal! Tudo certo? Bora começar uma série de posts sobre NestJS? A ideia aqui é criar um serviço bem simples de gerenciamento de tarefas, tipo um ToDo List mesmo. E, óbvio, vamos usar várias coisas que a gente usa todo dia quando tá construindo serviços.

O que é NestJS

NestJS é um framework top para criar aplicações em NodeJS com TypeScript. Ele é super modular e extensível. Para o servidor HTTP, ele usa o famoso ExpressJS. Mas, se você precisa de alta performance, pode ir de Fastify!

As features mais legais do Nest são a criação de módulos, injeção de dependências, uso de decorators e a facilidade para extender o código. No ecossistema, tem pacotes pra tudo: banco de dados (MySQL, Postgres, MongoDB), filas, microserviços. Borá começar!

Começando com o NestJS

Para criar nossso serviço, primeiro é necessário instalar o Nest CLI.

# pnpm
pnpm add -g @nestjs/cli

# npm
npm install -g @nestjs/cli

# yarn
yarn global add -g @nestjs/cli

Após instalar o Nest CLI, vamos criar nosso projeto em Nest:

nest new todo-list-service

Será solicitado qual gerenciado de pacotes você deseja usar. Eu particulamente prefiro o pnpm, por ser mais rápido que os outros. Após a conclusão do processo, você deverá ver dentro da pasta o projeto criado com essa estrutura:

todo-list-service
  |- src
    |- app.controller.spec.ts
    |- app.controller.ts
    |- app.module.ts
    |- app.service.ts
    |- main.ts
  |- tests
  |- package.json
  |- package-lock.json
  |- tsconfig.json
  |-...configuration-files

Primeiro endpoint

Quando o projeto é criado, é criado os arquivos main.ts, app.module.ts, app.controller.ts e app.service.ts. O arquivo main.ts é onde a aplicação é criada e iniciada. Isso acontece dentro do metódo bootstrap. Para criar a aplicação, é chamado o AppModule que é uma classe implementada no arquivo app.module.ts. Nessa classe com o decorator @Module() definimos quem são os controllers da nossa aplicação e quais são os providers. Além disso, é possível importar outros modulos.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController], // Controllers should be imported here
  providers: [AppService], // Providers should be imported here
})
export class AppModule {}

Para criar um endpoint, podemos ir no arquivo app.controller.ts. Nesse arquivo temos uma classe AppController com o decorator @Controller(). Cada endpoint é um método dessa classe com alguns desses decorators: @Get(), @Post, @Put, @Delete, @Patch, @Head, @Options, @Trace.

Quando a aplicação é criada, já temos um GET em / que retorna um Hello World!. Vamos adicionar mais um GET que será nosso healthcheck:

import { Controller, Get } from '@nestjs/common';

@Controller()
export class AppController {
  // Alrealdy implemented
  @Get()
  getHello(): string {
    return 'Hello World!';
  }

  @Get('health')
  getHealth() {
    return { status: 200, message: 'UP' };
  }
}

Dentro do decorator @Controller e nos decorators que mapeiam o verbo HTTP, podemos definir qual será a rota.

Por exemplo, caso tivessemos uma api de to-do’s, o controller poderia ser @Controller("todos"). Todo método mapeado como http request, irá responder usando a rota que começa com /todos. No get que busca um todo por id, no decorator get ficaria @Get(":id") e a rota final seria /todos/:id.

No caso do decorator controller estiver sem nenhum prefixo, então a rota irá responder a partir do root /.

Rodando o serviço

Agora que já criamos nosso primeiro endpoint, vamos rodar o serviço e fazer um get na api. Para rodar o serviço, vamos usar o script start:dev definido no package.json e chamar com algum gerenciador de pacotes do node:

# pnpm
pnpm start:dev

# npm
npm run start:dev

# yarn
yarn start:dev

Você deve ver algo assim no terminal:

[12:43:37 PM] File change detected. Starting incremental compilation...

[12:43:37 PM] Found 0 errors. Watching for file changes.

[Nest] 3173  - 02/07/2025, 12:43:38 PM     LOG [NestFactory] Starting Nest application...
[Nest] 3173  - 02/07/2025, 12:43:38 PM     LOG [InstanceLoader] AppModule dependencies initialized +2ms
[Nest] 3173  - 02/07/2025, 12:43:38 PM     LOG [RoutesResolver] AppController {/}: +0ms
[Nest] 3173  - 02/07/2025, 12:43:38 PM     LOG [RouterExplorer] Mapped {/, GET} route +0ms
[Nest] 3173  - 02/07/2025, 12:43:38 PM     LOG [RouterExplorer] Mapped {/error, POST} route +0ms
[Nest] 3173  - 02/07/2025, 12:43:38 PM     LOG [NestApplication] Nest application successfully started +0ms

A porta default do Nest é a 3000. Então provalmente o serviço irá responder chamadas http na url http://localhost:3000. Com o serviço rodando, vamos fazer nossa primeira request no serviço. Para isso, só chamar via curl:

curl -v  http://localhost:3000/health 

E você deve ver algo assim:

*   Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /health HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Access-Control-Allow-Origin: *
< Content-Type: application/json; charset=utf-8
< Content-Length: 29
< ETag: W/"1d-IDhexl3N5aiBtUkBl0nBxaLgj3A"
< Date: Fri, 07 Feb 2025 15:49:45 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
* Connection #0 to host localhost left intact
{"status":200,"message":"UP"}%

Muito bem! No próximo post vamos adicionar services e modules ao nosso serviço.

Gostou do artigo? Compartilhe nas redes sociais.