1. コントローラーとは何ですか?
コントローラーは処理を担当します 受信リクエスト そして戻る 応答。応答 クライアントのために。ルーティング メカニズムは、URL パスと HTTP メソッドに基づいて、どのコントローラーがどのリクエストを処理するかを決定します。
import { Controller, Get, Post, Put, Patch, Delete } from '@nestjs/common';
@Controller('products') // Base route: /products
export class ProductsController {
@Get() // GET /products
findAll() { return 'Tất cả sản phẩm'; }
@Get(':id') // GET /products/123
findOne() { return 'Một sản phẩm'; }
@Post() // POST /products
create() { return 'Tạo sản phẩm'; }
@Put(':id') // PUT /products/123
replace() { return 'Thay thế sản phẩm'; }
@Patch(':id') // PATCH /products/123
update() { return 'Cập nhật sản phẩm'; }
@Delete(':id') // DELETE /products/123
remove() { return 'Xóa sản phẩm'; }
}
2. アクセス要求オブジェクト
パラメータデコレータ
import {
Controller, Get, Post, Param, Query, Body,
Headers, Ip, Req, Res, HttpCode, Header,
} from '@nestjs/common';
import { Request, Response } from 'express';
@Controller('users')
export class UsersController {
// Route Parameters
@Get(':id')
findOne(@Param('id') id: string) { // /users/42 → id = '42'
return `User #${id}`;
}
// Multiple Route Params
@Get(':userId/posts/:postId')
findUserPost(
@Param('userId') userId: string,
@Param('postId') postId: string,
) {
return `User ${userId}, Post ${postId}`;
}
// Query Parameters
@Get()
findAll(
@Query('page') page: number = 1, // /users?page=2
@Query('limit') limit: number = 10, // /users?page=2&limit=20
@Query('search') search?: string, // /users?search=john
@Query() allQuery: Record<string, any>, // Tất cả query params
) {
return { page, limit, search };
}
// Request Body
@Post()
create(@Body() body: CreateUserDto) { // Full body
return body;
}
@Post('partial')
createPartial(@Body('name') name: string) { // Chỉ lấy field 'name'
return { name };
}
// Headers
@Get('info')
getInfo(
@Headers('authorization') auth: string,
@Headers('user-agent') userAgent: string,
@Ip() ip: string,
) {
return { auth, userAgent, ip };
}
// Full Request/Response objects (ít dùng)
@Get('raw')
getRaw(@Req() req: Request, @Res() res: Response) {
res.status(200).json({ url: req.url, method: req.method });
}
}
NestJS Decorators と Express の間のマッピング
| NestJS デコレータ | 特急相当品 |
|---|---|
@Req() | 要求 |
@Res() | レス |
@Param(キー) | req.params[キー] |
@Query(キー) | req.query[キー] |
@本体(キー) | req.body[キー] |
@ヘッダー(キー) | req.headers[キー] |
@Ip() | 要求IP |
@セッション() | 要求セッション |
3. 応答の処理
標準的なアプローチ (推奨)
@Controller('products')
export class ProductsController {
// Return object → tự động serialize thành JSON
@Get()
findAll(): Product[] {
return [{ id: 1, name: 'Laptop' }];
// Response: 200 OK, Content-Type: application/json
}
// Return string → plain text
@Get('health')
health(): string {
return 'OK';
// Response: 200 OK, Content-Type: text/html
}
// Return Promise → NestJS tự await
@Get('async')
async findAsync(): Promise<Product[]> {
return await this.productService.findAll();
}
// Return Observable → NestJS tự subscribe
@Get('stream')
findStream(): Observable<Product[]> {
return this.productService.findAllStream();
}
}
カスタムステータスコード
import { HttpCode, HttpStatus } from '@nestjs/common';
@Post()
@HttpCode(HttpStatus.CREATED) // 201
create(@Body() dto: CreateProductDto) {
return this.productService.create(dto);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT) // 204
remove(@Param('id') id: string) {
this.productService.remove(id);
}
カスタム応答ヘッダー
@Get()
@Header('Cache-Control', 'max-age=3600')
@Header('X-Custom-Header', 'NestJS')
findAll() {
return this.productService.findAll();
}
リダイレクト
import { Redirect } from '@nestjs/common';
@Get('old-page')
@Redirect('/new-page', 301) // Permanent redirect
oldPage() {}
// Dynamic redirect
@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version: string) {
if (version === 'v11') {
return { url: 'https://docs.nestjs.com/v11' };
}
// Nếu không return gì, dùng URL mặc định
}
4. ルートワイルドカードとパターンマッチング
// Wildcard routes
@Get('ab*cd') // Matches: abcd, ab_cd, abecd, ab123cd,...
findWild() {
return 'This route uses a wildcard';
}
// Regex-based param (NestJS dùng path-to-regexp)
@Get(':id(\\d+)') // Chỉ match số: /products/123 ✓, /products/abc ✗
findOne(@Param('id') id: string) {
return `Product #${id}`;
}
5. DTO — データ転送オブジェクト
// src/products/dto/create-product.dto.ts
export class CreateProductDto {
name: string;
description: string;
price: number;
category: string;
inStock: boolean;
}
// src/products/dto/update-product.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateProductDto } from './create-product.dto';
// PartialType tạo class mới với tất cả fields optional
export class UpdateProductDto extends PartialType(CreateProductDto) {}
// Sử dụng
@Post()
create(@Body() dto: CreateProductDto) {
// TypeScript đảm bảo dto có đúng shape
return this.service.create(dto);
}
@Patch(':id')
update(@Param('id') id: string, @Body() dto: UpdateProductDto) {
return this.service.update(+id, dto);
}
6. API のバージョン管理
// main.ts — Bật versioning
import { VersioningType } from '@nestjs/common';
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.URI, // /v1/users, /v2/users
// type: VersioningType.HEADER, // Header: X-API-Version: 1
// type: VersioningType.MEDIA_TYPE, // Accept: application/json;v=1
});
// Controller
@Controller({ path: 'users', version: '1' })
export class UsersV1Controller {
@Get()
findAll() { return 'V1 users'; }
}
@Controller({ path: 'users', version: '2' })
export class UsersV2Controller {
@Get()
findAll() { return 'V2 users with pagination'; }
}
// Per-route versioning
@Controller('users')
export class UsersController {
@Version('1')
@Get()
findAllV1() { return 'V1'; }
@Version('2')
@Get()
findAllV2() { return 'V2'; }
}
7. まとめ
- コントローラー でマークされた HTTP リクエストを処理します。
@コントローラー() - パラメータデコレータ:
@Param()、@Query()、@ボディ()、@ヘッダー() - 応答: オブジェクト (JSON)、文字列 (テキスト)、または Promise/Observable を返します。
- DTO: クラスは使用されるデータの形状を定義します
部分型アップデート用 - バージョン管理: URI、ヘッダーまたはメディア タイプ
次の記事で詳しく説明します プロバイダーと依存関係の注入 — NestJS のコアメカニズム。