NestJS — Enterprise Node.js

Controllers: Handling Requests

15 min Lesson 4 of 30

Controllers: Handling Requests

Controllers are the entry point for incoming requests. Their job is narrow and important: receive a request, delegate the work to a service, and return a response. Keeping controllers thin — routing only, no business logic — is one of the most important habits in NestJS.

Defining a controller

A controller is a class decorated with @Controller(). The string you pass becomes the route prefix for every method inside:

import { Controller, Get } from '@nestjs/common'; @Controller('users') export class UsersController { @Get() findAll() { return 'This returns all users'; } }

Here @Controller('users') + @Get() maps to GET /users.

HTTP method decorators

Each HTTP verb has a decorator: @Get(), @Post(), @Put(), @Patch(), @Delete(). Pass a path segment to extend the route:

@Controller('users') export class UsersController { @Get() // GET /users findAll() {} @Get('active') // GET /users/active findActive() {} @Post() // POST /users create() {} }

Reading route parameters

Dynamic segments use :name in the path and the @Param() decorator to read them:

import { Controller, Get, Param } from '@nestjs/common'; @Controller('users') export class UsersController { @Get(':id') // GET /users/42 findOne(@Param('id') id: string) { return `User #${id}`; } }
Route params are always strings. A value like 42 arrives as the string '42'. Converting and validating it is the job of pipes, covered later in this course.

Query parameters and the request body

Use @Query() for the query string and @Body() for the request payload:

import { Controller, Get, Post, Query, Body } from '@nestjs/common'; @Controller('users') export class UsersController { @Get() // GET /users?role=admin findAll(@Query('role') role: string) { return `Users with role ${role}`; } @Post() // POST /users + JSON body create(@Body() body: { name: string; email: string }) { return body; } }
Prefer decorators over the raw request. NestJS can inject the underlying request with @Req(), but using @Param(), @Query(), and @Body() keeps your handlers framework-agnostic, typed, and far easier to test.

Status codes and responses

By default NestJS returns 200 (and 201 for @Post()). Override with @HttpCode(), and whatever you return is automatically serialised to JSON:

import { Controller, Post, HttpCode } from '@nestjs/common'; @Controller('sessions') export class SessionsController { @Post('login') @HttpCode(200) // override the default 201 login() { return { token: 'abc123' }; // serialised to JSON automatically } }
Keep controllers thin. A controller should not query a database, send emails, or contain business rules. Inject a service and call it. Thin controllers are the difference between a maintainable app and a tangled one.

Summary

Controllers map requests to handler methods using @Controller() and the HTTP-verb decorators, and read input with @Param(), @Query(), and @Body(). Returned values are serialised to JSON automatically. The golden rule: controllers route, services do the work. Next we will build those services.