# Controllers and routing

> Source: https://learn-nestjs.com/controllers/
> Part of Learn NestJS, free to read.

A controller maps HTTP to method calls. The discipline that keeps a Nest codebase healthy is that it does nothing else.

```ts src/users/users.controller.ts
import {
  Controller, Get, Post, Patch, Delete,
  Param, Query, Body, HttpCode, ParseIntPipe,
} from '@nestjs/common';

@Controller('users')
export class UsersController {
  constructor(private readonly users: UsersService) {}

  @Get()
  findAll(@Query('limit', ParseIntPipe) limit = 20) {
    return this.users.findAll(limit);
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.users.findOne(id);
  }

  @Post()
  @HttpCode(201)
  create(@Body() dto: CreateUserDto) {
    return this.users.create(dto);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() dto: UpdateUserDto) {
    return this.users.update(id, dto);
  }

  @Delete(':id')
  @HttpCode(204)
  remove(@Param('id') id: string) {
    return this.users.remove(id);
  }
}
```

Every method is one line. That is the target.

## Return values

Return an object and Nest serialises it as JSON with a 200 (or 201 for `@Post`). Return a promise and it awaits it. Return an Observable and it subscribes.

You almost never need the raw response object. If you take `@Res()`, you opt out of Nest's serialisation entirely and become responsible for ending the response yourself — a common source of hung requests.

```ts
// avoid unless you genuinely need streaming or a redirect
@Get('download')
download(@Res() res: Response) {
  res.setHeader('Content-Type', 'text/csv');
  res.send(csv);           // you must end it. Nest will not.
}
```

Use `@Res({ passthrough: true })` when you only need to set a header or a cookie and still want Nest to serialise the return value.

## Route parameters and order

```ts
@Get('me')            // must come before ':id'
me() {}

@Get(':id')
findOne(@Param('id') id: string) {}
```

Routes match in declaration order. `@Get(':id')` declared first will swallow `/users/me`. This is one of the two or three most common Nest bugs.

## Status codes and headers

```ts
@Post()
@HttpCode(201)
@Header('Cache-Control', 'no-store')
create(@Body() dto: CreateUserDto) {}

@Get('old')
@Redirect('/users', 301)
old() {}
```

## Sub-resources

```ts
@Controller('users/:userId/orders')
export class UserOrdersController {
  @Get()
  list(@Param('userId') userId: string) {
    return this.orders.forUser(userId);
  }
}
```

:::warn Authorisation is not routing
`/users/:userId/orders` says nothing about whether the caller may read *that* user's orders. Checking that the authenticated user matches `userId` is a guard's job, and forgetting it is the most common real vulnerability in generated back-end code. See [reviewing generated NestJS](/review/failure-modes/).
:::

## Common questions

### Should validation happen in the controller?

Declare it — with a DTO class and decorators — and let the global `ValidationPipe` enforce it. That is the controller declaring its contract, not implementing logic. Business rules ("this email is already taken") belong in the service.

### Where does error handling go?

Throw a Nest exception (`NotFoundException`, `ForbiddenException`) from the service, and let the built-in exception filter turn it into a response. Controllers should not contain `try/catch` in the normal case.

### Why is my `:id` route catching everything?

Because a more specific literal route is declared after it. Move static segments (`me`, `search`, `export`) above parameterised ones.
