Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
ramziddin avatar

Controllers

  • 2 installs
  • 1 repo stars
  • Updated January 2, 2026
  • ramziddin/ccplugins

Reference for NestJS controllers: routing, HTTP methods, route and query parameters, request bodies, and responses.

About

Covers building REST API endpoints in NestJS with controllers, decorators, routing, and request/response handling. A developer uses it when creating HTTP endpoints or handling route data.

  • Maps routes with @Controller and HTTP-method decorators
  • Handles params, query, body, headers, status codes, and redirects

Controllers by the numbers

  • 2 all-time installs (skills.sh)
  • Ranked #3,765 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ramziddin/ccplugins --skill controllers

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs2
repo stars1
Last updatedJanuary 2, 2026
Repositoryramziddin/ccplugins

What it does

Reference for NestJS controllers: routing, HTTP methods, route and query parameters, request bodies, and responses.

Files

SKILL.mdMarkdownGitHub ↗

NestJS Controllers

When to Use This Skill

Use this skill when:

  • Creating REST API endpoints
  • Handling HTTP requests (GET, POST, PUT, DELETE, PATCH)
  • Working with route parameters, query parameters, or request bodies
  • Setting up routing and path prefixes
  • Handling redirects, headers, or status codes
  • Working with async/await in route handlers

What are Controllers?

Controllers are responsible for handling incoming requests and returning responses to the client. They use decorators to map routes to handler methods.

Basic Controller

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

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}

Key Points:

  • @Controller('cats') - Sets route prefix /cats
  • @Get() - Maps GET requests to this method
  • Returns value automatically serialized to JSON (objects/arrays)
  • Must register controller in module's controllers array

HTTP Method Decorators

import { Controller, Get, Post, Put, Delete, Patch } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll() {
    return [];
  }

  @Post()
  create() {
    return 'Created';
  }

  @Put(':id')
  update() {
    return 'Updated';
  }

  @Delete(':id')
  remove() {
    return 'Deleted';
  }

  @Patch(':id')
  patch() {
    return 'Patched';
  }
}

Route Parameters

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

@Controller('cats')
export class CatsController {
  @Get(':id')
  findOne(@Param('id') id: string) {
    return `This action returns cat #${id}`;
  }

  // Multiple parameters
  @Get(':category/:id')
  findByCategory(
    @Param('category') category: string,
    @Param('id') id: string
  ) {
    return `Category: ${category}, ID: ${id}`;
  }

  // All params as object
  @Get(':id')
  findOneAlt(@Param() params: { id: string }) {
    return `Cat #${params.id}`;
  }
}

Query Parameters

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

@Controller('cats')
export class CatsController {
  // /cats?limit=10&offset=0
  @Get()
  findAll(
    @Query('limit') limit: string,
    @Query('offset') offset: string
  ) {
    return `Limit: ${limit}, Offset: ${offset}`;
  }

  // All query params as object
  @Get()
  findAllAlt(@Query() query: { limit: string; offset: string }) {
    return query;
  }
}

Request Body

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

export class CreateCatDto {
  name: string;
  age: number;
  breed: string;
}

@Controller('cats')
export class CatsController {
  @Post()
  create(@Body() createCatDto: CreateCatDto) {
    return `Creating cat: ${createCatDto.name}`;
  }

  // Specific property
  @Post()
  createAlt(@Body('name') name: string) {
    return `Creating cat: ${name}`;
  }
}

Request Object

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

@Controller('cats')
export class CatsController {
  @Get()
  findAll(@Req() request: Request) {
    return request.headers;
  }
}

Available Request Decorators:

  • @Request(), @Req() - Full request object
  • @Response(), @Res() - Full response object (use with caution)
  • @Next() - Next function
  • @Session() - Session object
  • @Param(key?) - Route parameters
  • @Body(key?) - Request body
  • @Query(key?) - Query parameters
  • @Headers(key?) - Request headers
  • @Ip() - Client IP address
  • @HostParam() - Host parameters

Status Codes

import { Controller, Post, HttpCode, HttpStatus } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  // Default: 200 for GET, 201 for POST
  @Post()
  create() {
    return 'Created';
  }

  // Custom status code
  @Post()
  @HttpCode(HttpStatus.NO_CONTENT)
  createNoContent() {
    // Returns 204
  }

  @Post()
  @HttpCode(204)
  createAlt() {
    // Also returns 204
  }
}

Response Headers

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

@Controller('cats')
export class CatsController {
  @Post()
  @Header('Cache-Control', 'no-store')
  @Header('X-Custom-Header', 'value')
  create() {
    return 'Created with custom headers';
  }
}

Redirection

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

@Controller('cats')
export class CatsController {
  @Get('docs')
  @Redirect('https://docs.nestjs.com', 301)
  getDocs() {
    // Redirects to docs
  }

  // Dynamic redirect
  @Get('search')
  @Redirect()
  search(@Query('term') term: string) {
    return {
      url: `https://google.com/search?q=${term}`,
      statusCode: 302
    };
  }
}

Route Wildcards

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

@Controller('cats')
export class CatsController {
  // Matches: /cats/profile, /cats/p, /cats/prxfile
  @Get('ab*cd')
  findWildcard() {
    return 'Wildcard route';
  }
}

Supported wildcards: *, ?, +, ()

Sub-Domain Routing

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

@Controller({ host: ':account.example.com' })
export class AccountController {
  @Get()
  getInfo(@HostParam('account') account: string) {
    return `Account: ${account}`;
  }
}

Async Handlers

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

@Controller('cats')
export class CatsController {
  @Get()
  async findAll(): Promise<Cat[]> {
    return await this.catsService.findAll();
  }

  // Using Observables (RxJS)
  @Get()
  findAllRx(): Observable<Cat[]> {
    return of([]);
  }
}

DTOs (Data Transfer Objects)

// create-cat.dto.ts
export class CreateCatDto {
  name: string;
  age: number;
  breed: string;
}

// cats.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';

@Controller('cats')
export class CatsController {
  @Post()
  create(@Body() createCatDto: CreateCatDto) {
    return createCatDto;
  }
}

Why use classes instead of interfaces?

  • Classes are preserved at runtime (interfaces are not)
  • Enables validation with class-validator
  • Works with Pipes for transformation

Complete Controller Example

import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { UpdateCatDto } from './dto/update-cat.dto';
import { CatsService } from './cats.service';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Get()
  findAll(@Query('limit') limit = 10) {
    return this.catsService.findAll(limit);
  }

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

  @Post()
  @HttpCode(HttpStatus.CREATED)
  create(@Body() createCatDto: CreateCatDto) {
    return this.catsService.create(createCatDto);
  }

  @Put(':id')
  update(
    @Param('id') id: string,
    @Body() updateCatDto: UpdateCatDto
  ) {
    return this.catsService.update(id, updateCatDto);
  }

  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)
  remove(@Param('id') id: string) {
    return this.catsService.remove(id);
  }
}

Registering Controllers

Controllers must be registered in a module:

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

Best Practices

1. Keep controllers thin - Delegate business logic to services 2. Use DTOs - Define classes for request/response data 3. Validate input - Use ValidationPipe with class-validator 4. Use dependency injection - Inject services via constructor 5. Handle errors properly - Throw appropriate HTTP exceptions 6. Use async/await - For asynchronous operations 7. Document APIs - Use @nestjs/swagger for OpenAPI docs 8. Consistent naming - Use standard REST conventions

Common Patterns

Resource Controller Pattern

nest generate resource cats

This generates:

  • Module
  • Controller with CRUD routes
  • Service
  • DTOs (create, update)
  • Entity

Nested Routes

@Controller('users/:userId/posts')
export class PostsController {
  @Get()
  findUserPosts(@Param('userId') userId: string) {
    return this.postsService.findByUser(userId);
  }
}

Versioning

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

@Controller('cats')
export class CatsController {
  @Version('1')
  @Get()
  findAllV1() {
    return 'V1';
  }

  @Version('2')
  @Get()
  findAllV2() {
    return 'V2';
  }
}

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.