← 返回AI变现
🌐 其他
NestJS 全栈 CRUD 实战:从 Module 拆分到 RESTful 七大装饰器,彻底搞懂后端接口工程
NestJS 全栈 CRUD 实战:从 Module 拆分到 RESTful 七大装饰器,彻底搞懂后端接口工程 一、NestJS 开发流程全景 1.1 从单模块到多模块的演进 1.2 NestJS 模
NestJS å ¨æ CRUD 宿ï¼ä» Module æåå° RESTful ä¸å¤§è£ 饰å¨ï¼å½»åºææå端æ¥å£å·¥ç¨
Darlingåå¦å¦ 2026-08-19 0 é 读13åéNestJS å ¨æ CRUD 宿ï¼ä» Module æåå° RESTful ä¸å¤§è£ 饰å¨ï¼å½»åºææå端æ¥å£å·¥ç¨
ä¸ç¯æä»¬ç¨èéªå°åçè§£äºå·¥å模å¼åè£ é¥°å¨æ¨¡å¼ï¼ææ¡äº NestJS ç设计å²å¦ãè¿ç¯è¿å ¥å®æââç¨ NestJS ä»é¶æå»ºä¸ä¸ªå®æ´ç Todos CRUD æ¥å£ã仿 ¹æ¨¡åæå忍¡åï¼å° Controller çäºå¤§ HTTP è£ é¥°å¨ãService çä¸å¡é»è¾ä¸é误å¤çï¼åå°
@Param@Bodyåæ°æååPartial<T>ç±»åæå·§ââä¸ç¯æç« æéå端æ¥å£å·¥ç¨ç宿´é¾è·¯ãå ¨æä»£ç å¯ç´æ¥è¿è¡ï¼å»ºè®®æ¶èå卿å®è·µã
ä¸ãNestJS å¼åæµç¨å ¨æ¯
1.1 ä»å模åå°å¤æ¨¡åçæ¼è¿
ä¸ç¯ï¼åæ¨¡åæ¶æï¼å¦ä¹ é¶æ®µï¼
src/
âââ main.ts # å
¥å£
âââ app.module.ts # æ ¹æ¨¡åï¼ææåè½å å¨ä¸èµ·ï¼
âââ app.controller.ts # æ ¹æ§å¶å¨
âââ app.service.ts # æ ¹æå¡
æ¬ç¯ï¼å¤æ¨¡åæ¶æï¼ä¼ä¸çº§ï¼
src/
âââ main.ts # å
¥å£
âââ app.module.ts # æ ¹æ¨¡åï¼imports 忍¡åï¼
âââ app.controller.ts # æ ¹æ§å¶å¨
âââ app.service.ts # æ ¹æå¡
âââ todos/ # Todos ä¸å¡æ¨¡å
âââ todos.module.ts # 模åå®ä¹ï¼ç»è£
Controller + Serviceï¼
âââ Todos.controller.ts # æ§å¶å¨ï¼è·¯ç± + åæ°æ ¡éªï¼
âââ Todos.service.ts # æå¡ï¼ä¸å¡é»è¾ + æ°æ®æä½ï¼
1.2 NestJS 模åå¼å约å®
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â NestJS 模åå¼åæµç¨ â
â â
â â AppModule ç imports 䏿¤å
¥ä¸å¡æ¨¡å â
â â @Module({ imports: [TodosModule] }) â
â â
â â¡ æ¯ä¸ªä¸å¡æ¨¡åæ¯ç¬ç«ç MVC åå
â
â â xx.module.ts å®ä¹æ¨¡åï¼ç»è£
Controller + Service â
â â xx.controller.ts æ§å¶å¨ï¼å¤ç HTTP è¯·æ± â
â â xx.service.ts æå¡å±ï¼å¤çä¸å¡é»è¾ â
â â
â ⢠Service ç¨ @Injectable() æ è®° â
â â èªå¨ä¾èµæ³¨å
¥å° Controller â
â â Controller æé 彿°ä¸å£°æä¾èµ â
â â ä¸éè¦æå¨ newï¼NestJS DI 容å¨ç®¡ç â
â â
â ⣠Controller ä¸ç´æ¥æä½æ°æ®åº â
â â éè¿ Service é´æ¥æä½ â
â â MVC åå±ï¼View(Controller) â Model(Service) â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
1.3 RESTful API 设计
Todos æ¥å£è®¾è®¡ï¼RESTful 飿 ¼ï¼ï¼
HTTP æ¹æ³ è·¯å¾ åè½ NestJS è£
饰å¨
ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
GET /todos è·åææ @Get()
GET /todos/:id è·åå个 @Get(':id')
POST /todos å建 @Post()
DELETE /todos/:id å é¤ @Delete(':id')
PATCH /todos/:id é¨åæ´æ° @Patch(':id')
RESTful æ ¸å¿ï¼
âââ ç¨ HTTP æ¹æ³åºåæä½ç±»åï¼GET/POST/DELETE/PATCHï¼
âââ ç¨ URL è·¯å¾å®ä½èµæºï¼/todos/:idï¼
âââ ç¨ HTTP ç¶æç è¡¨è¾¾ç»æï¼200/201/404/204ï¼
âââ ç¨ JSON ä½ä¸ºæ°æ®æ ¼å¼
äºãæ ¹æ¨¡åï¼AppModule æ¤å ¥å模å
2.1 app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TodosModule } from './todos/todos.module';
@Module({
imports: [TodosModule], // æ¤å
¥ Todos ä¸å¡æ¨¡å
controllers: [AppController], // æ ¹æ§å¶å¨
providers: [AppService], // æ ¹æå¡
})
export class AppModule {}
å ³é®ååï¼
ä¹åï¼å模åï¼ï¼
@Module({
imports: [], // 没æå模å
controllers: [AppController],
providers: [AppService],
})
ç°å¨ï¼å¤æ¨¡åï¼ï¼
@Module({
imports: [TodosModule], // â æ¤å
¥ä¸å¡æ¨¡å
controllers: [AppController],
providers: [AppService],
})
imports çä½ç¨ï¼
â åè¯ AppModule "æä¾èµ TodosModule"
â NestJS å¯å¨æ¶ä¼èªå¨å è½½ TodosModule
â TodosModule ä¸ç Controller å Service ä¼è¢«æ³¨å
â è·¯ç± /todos ä¼è¢«æ¿æ´»
模åä¾èµå
³ç³»å¾ï¼
AppModuleï¼æ ¹æ¨¡åï¼
â
âââ imports: [TodosModule] â æ¤å
¥
â â
â âââ controllers: [TodosController] â è·¯ç± /todos
â âââ providers: [TodosService] â ä¸å¡é»è¾
â
âââ controllers: [AppController] â è·¯ç± /
âââ providers: [AppService] â æ ¹æå¡
ä¸ã模åå®ä¹ï¼TodosModule çç»è£
3.1 todos.module.ts
import { Module } from '@nestjs/common';
import { TodosController } from './Todos.controller';
import { TodosService } from './Todos.service';
@Module({
controllers: [TodosController], // æ³¨åæ§å¶å¨
providers: [TodosService], // 注åæå¡ï¼å¯è¢«æ³¨å
¥ï¼
})
export class TodosModule {}
模åçèè´£ï¼
TodosModule å°±æ¯ä¸ä¸ª"è£
é
车é´"ï¼
ââââââââââââââââââââââââââââââââââââââââââââââââ
â TodosModuleï¼è£
é
车é´ï¼ â
â â
â controllers: [TodosController] â
â â æ³¨åæ§å¶å¨ï¼æ¿æ´» /todos è·¯ç± â
â â
â providers: [TodosService] â
â â æ³¨åæå¡ï¼æ¾å
¥ DI å®¹å¨ â
â â TodosController éè¦æ¶èªå¨æ³¨å
¥ â
â â
â æ¨¡åä¸åä¸å¡é»è¾ï¼åªè´è´£"ç»è£
" â
ââââââââââââââââââââââââââââââââââââââââââââââââ
MVC åå±ååï¼
Viewå±ï¼Controllerï¼
â ä¸å¯ä»¥ç´æ¥å»æ°æ®åºæ¥æ°æ®
â åªæ¥æ¶è¯·æ±ãæ ¡éªåæ°ãè°ç¨ Serviceãè¿åååº
Modelå±ï¼Serviceï¼
â å¤çä¸å¡é»è¾
â æ°æ®åº CRUD
â æ°æ®å¤çä¸è½¬æ¢
NestJS ç MVCï¼
V = Controllerï¼è§å¾å± = JSON ååºï¼
C = Controller ä¸çè·¯ç±é»è¾
M = Service + æ°æ®åº
åãæ§å¶å¨å±ï¼äºå¤§ HTTP è£ é¥°å¨
4.1 Todos.controller.ts 宿´ä»£ç
import {
Controller,
Get,
Post,
Delete,
Patch,
Param,
Body,
} from '@nestjs/common';
import { TodosService } from './Todos.service';
import type { Todo } from './Todos.service';
@Controller('todos')
export class TodosController {
constructor(private readonly todosService: TodosService) {}
// GET /todos â è·åææ
@Get()
findAll(): Todo[] {
return this.todosService.findAll();
}
// GET /todos/:id â è·åå个
@Get(':id')
findOne(@Param('id') id: string): Todo {
return this.todosService.findOne(Number(id));
}
// POST /todos â å建
@Post()
create(@Body('title') title: string): Todo {
return this.todosService.create(title);
}
// DELETE /todos/:id â å é¤
@Delete(':id')
remove(@Param('id') id: string): { message: string } {
this.todosService.remove(Number(id));
return { message: 'success' };
}
// PATCH /todos/:id â é¨åæ´æ°
@Patch(':id')
update(@Param('id') id: string, @Body() patch: Partial<Todo>): Todo {
return this.todosService.update(Number(id), patch);
}
}
4.2 ç±»è£ é¥°å¨ï¼@Controller('todos')
@Controller('todos')
export class TodosController { ... }
@Controller('todos') çä½ç¨ï¼
â ç»æ§å¶å¨è®¾ç½®è·¯ç±åç¼ 'todos'
â æ§å¶å¨å
ææè·¯ç±é½èªå¨å ä¸ /todos åç¼
@Get() â GET /todos
@Get(':id') â GET /todos/:id
@Post() â POST /todos
@Delete(':id') â DELETE /todos/:id
@Patch(':id') â PATCH /todos/:id
没æ @Controller('todos') çè¯ï¼
@Get() â GET / â è·¯å¾å²çª
@Get(':id') â GET /:id â åå
¶ä»æ§å¶å¨å²çª
è·¯ç±åç¼è®©å¤ä¸ªæ§å¶å¨å管åçèµæºï¼äºä¸å²çª
4.3 æ¹æ³è£ 饰å¨ï¼äºå¤§ HTTP æ¹æ³
@Get() // GET â æ¥è¯¢èµæº
@Get(':id') // GET â æ¥è¯¢åä¸ªèµæº
@Post() // POST â åå»ºèµæº
@Delete(':id') // DELETE â å é¤èµæº
@Patch(':id') // PATCH â é¨åæ´æ°èµæº
HTTP æ¹æ³ä¸ CRUD ç对åºå
³ç³»ï¼
Cï¼Createï¼ â POST â å建æ°èµæº
Rï¼Readï¼ â GET â æ¥è¯¢èµæº
Uï¼Updateï¼ â PATCH â é¨åæ´æ°ï¼åªæ¹ä¼ äºçåæ®µï¼
â PUT â å
¨éæ´æ°ï¼æ¿æ¢æ´ä¸ªèµæºï¼
Dï¼Deleteï¼ â DELETE â å é¤èµæº
PATCH vs PUT çåºå«ï¼
PATCH /todos/1 { "complete": true }
â åªæ¹ complete åæ®µï¼title ä¸å
PUT /todos/1 { "title": "æ°æ é¢", "complete": true }
â æ´ä¸ªæ¿æ¢ï¼å¿
é¡»ä¼ ææå段
NestJS æ¯æç HTTP æ¹æ³è£
饰å¨ï¼
@Get() â GET æ¥è¯¢
@Post() â POST å建
@Put() â PUT å
¨éæ´æ°
@Patch() â PATCH é¨åæ´æ°
@Delete() â DELETE å é¤
@All() â æææ¹æ³ é½å¹é
@Head() â HEAD åªè·å头信æ¯
@Options() â OPTIONS 颿£è¯·æ±
4.4 åæ°è£ é¥°å¨ï¼@Param å @Body
// @Param('id') â ä» URL è·¯å¾ä¸æååæ°
@Get(':id')
findOne(@Param('id') id: string): Todo {
return this.todosService.findOne(Number(id));
}
// è¯·æ± GET /todos/5
// @Param('id') â id = '5'ï¼æ³¨æï¼URL åæ°æ°¸è¿æ¯ stringï¼
// @Body('title') â ä»è¯·æ±ä½ä¸æåæå®å段
@Post()
create(@Body('title') title: string): Todo {
return this.todosService.create(title);
}
// è¯·æ± POST /todos
// Body: { "title": "å¦ä¹ NestJS" }
// @Body('title') â title = 'å¦ä¹ NestJS'
// @Body() â æåæ´ä¸ªè¯·æ±ä½
@Patch(':id')
update(@Param('id') id: string, @Body() patch: Partial<Todo>): Todo {
return this.todosService.update(Number(id), patch);
}
// è¯·æ± PATCH /todos/1
// Body: { "complete": true }
// @Body() â patch = { complete: true }
NestJS åæ°è£
饰å¨å
¨å®¶æ¡¶ï¼
@Param('id') â URL è·¯å¾åæ° /todos/:id â id
@Body('title') â 请æ±ä½æå®å段 { title: 'xxx' } â title
@Body() â æ´ä¸ªè¯·æ±ä½ { title, complete } â æ´ä¸ªå¯¹è±¡
@Query('page') â æ¥è¯¢åæ° /todos?page=1 â page
@Headers('auth') â 请æ±å¤´æå®å段 Authorization: Bearer xxx
@Req() â æ´ä¸ª Request 对象
@Res() â æ´ä¸ª Response 对象
åæ°è£
饰å¨çä»·å¼ï¼
â 声æå¼è·å请æ±åæ°ï¼ä¸éè¦æå¨è§£æ
â TypeScript ç±»åæ æ³¨ï¼ç¼è¯æ¶æ£æ¥
â åªåéè¦çåæ®µï¼ä¸å¼å
¥æ´ä¸ª Request 对象
4.5 ä¾èµæ³¨å ¥ï¼æé 彿°æ³¨å ¥ Service
@Controller('todos')
export class TodosController {
constructor(private readonly todosService: TodosService) {}
// â â â
// â â âââ ç±»åï¼TodosService
// â â â NestJS æ ¹æ®ç±»åä» DI 容卿¾å®ä¾
// â âââ readonlyï¼åªè¯»ï¼é²æ¢å¨æ§å¶å¨ä¸ä¿®æ¹ Service
// âââ privateï¼ç§æå±æ§ï¼ç±»å¤é¨ä¸å¯è®¿é®
// 注å
¥åç´æ¥ä½¿ç¨
@Get()
findAll(): Todo[] {
return this.todosService.findAll();
// âââ ä¸éè¦æå¨ new TodosService()
// NestJS èªå¨å建并注å
¥å®ä¾
}
}
ä¾èµæ³¨å ¥ç宿´æµç¨ï¼
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â ä¾èµæ³¨å
¥ï¼DIï¼å®æ´æµç¨ â
â â
â 1. TodosService 类被 @Injectable() æ è®° â
â â "ææ¯ä¸ä¸ªå¯è¢«æ³¨å
¥çæå¡" â
â â
â 2. TodosModule ç providers 注åäº TodosService â
â â NestJS DI 容å¨å建并管ç TodosService å®ä¾ â
â â
â 3. TodosController æé 彿°å£°æéè¦ TodosService â
â constructor(private readonly todosService: TodosService)â
â â NestJS çå°ç±»åæ¯ TodosService â
â â ä» DI 容å¨ä¸ååºå®ä¾ â
â â èªå¨æ³¨å
¥å°æé 彿°åæ° â
â â
â 4. æ§å¶å¨ä¸ç´æ¥ this.todosService.findAll() â
â â ä¸å
³å¿å®ä¾æä¹æ¥çï¼åªç®¡ç¨ â
â â
â è¿å°±æ¯"æ§å¶å转"ï¼IoCï¼ï¼ â
â 对象çå建æ§å¶æä»å¼åè
转移å°äºæ¡æ¶ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
äºãæå¡å±ï¼ä¸å¡é»è¾ä¸é误å¤ç
5.1 Todos.service.ts 宿´ä»£ç
import {
Injectable,
NotFoundException,
} from '@nestjs/common';
// æ°æ®æ¨¡åæ¥å£
export interface Todo {
id: number;
title: string;
complete: boolean;
}
// å
åæ°æ®æºï¼å®é
项ç®ä¸æ¿æ¢ä¸ºæ°æ®åºï¼
let todos: Todo[] = [
{ id: 1, title: 'å¦ä¹ NestJS', complete: false },
{ id: 2, title: 'å¦ä¹ CRUD', complete: true },
];
let nextId = 3; // èªå¢ ID
@Injectable()
export class TodosService {
// æ¥è¯¢ææ
findAll(): Todo[] {
return todos;
}
// æ¥è¯¢å个
findOne(id: number): Todo {
const todo = todos.find(t => t.id === id);
if (!todo) throw new NotFoundException(`Todo ${id} ä¸åå¨`);
return todo;
}
// å建
create(title: string): Todo {
const todo: Todo = { id: nextId++, title, complete: false };
todos.push(todo);
return todo;
}
// å é¤
remove(id: number): void {
const index = todos.findIndex(t => t.id === id);
if (index === -1) throw new NotFoundException(`Todo ${id} ä¸åå¨`);
todos.splice(index, 1);
}
// é¨åæ´æ°
update(id: number, patch: Partial<Todo>): Todo {
const todo = todos.find(t => t.id === id);
if (!todo) throw new NotFoundException(`Todo ${id} ä¸åå¨`);
Object.assign(todo, patch);
return todo;
}
}
5.2 æ°æ®æ¨¡å设计
export interface Todo {
id: number; // å¯ä¸æ è¯
title: string; // 任塿 é¢
complete: boolean; // æ¯å¦å®æ
}
TypeScript interface çç¹ç¹ï¼
interface Todo { ... }
â åªæè¿°æ°æ®ç»æï¼ç¼è¯åä¼è¢«å®å
¨ç§»é¤
â ä¸äº§çè¿è¡æ¶ä»£ç
â ç¨äºç±»åæ£æ¥ï¼ä¸å è¿è¡æ¶ä½ç§¯
let todos: Todo[] = [ ... ]
let nextId = 3;
â ç¨ let èé constï¼æ°æ®éè¦å¢å æ¹
â nextId èªå¢ ID çæå¨
â å®é
项ç®ä¸ç¨æ°æ®åºçèªå¢ ID
5.3 äºå¤§ä¸å¡æ¹æ³é个æè§£
â findAll()ï¼æ¥å ¨é¨
findAll(): Todo[] {
return todos;
}
// ç´æ¥è¿åæ´ä¸ªæ°ç»
// å®é
项ç®ä¸ä¼å å页ãè¿æ»¤ãæåº
â¡ findOne(id)ï¼æ¥å个 + é误å¤ç
findOne(id: number): Todo {
const todo = todos.find(t => t.id === id);
if (!todo) throw new NotFoundException(`Todo ${id} ä¸åå¨`);
return todo;
}
// find æ¾ä¸å°è¿å undefinedï¼ä¸æ¯æ¥é
// éè¦æå¨æ£æ¥å¹¶æåº NotFoundException
// NestJS 伿 NotFoundException 转æ HTTP 404 ååº
⢠create(title)ï¼å建
create(title: string): Todo {
const todo: Todo = { id: nextId++, title, complete: false };
todos.push(todo);
return todo;
}
// nextId++ â å
ç¨å½åå¼ï¼åèªå¢
// æ°ä»»å¡é»è®¤ complete: falseï¼æªå®æï¼
// è¿åå建ç todoï¼å
å«åé
ç idï¼
⣠remove(id)ï¼å é¤
remove(id: number): void {
const index = todos.findIndex(t => t.id === id);
if (index === -1) throw new NotFoundException(`Todo ${id} ä¸åå¨`);
todos.splice(index, 1);
}
// findIndex æ¾ç´¢å¼ï¼æ¾ä¸å°è¿å -1
// splice(index, 1) 仿°ç»ä¸å é¤ä¸ä¸ªå
ç´
// è¿å void â Controller ä¸å
è£
æ { message: 'success' }
⤠update(id, patch)ï¼é¨åæ´æ°
update(id: number, patch: Partial<Todo>): Todo {
const todo = todos.find(t => t.id === id);
if (!todo) throw new NotFoundException(`Todo ${id} ä¸åå¨`);
Object.assign(todo, patch);
return todo;
}
// Partial<Todo> â Todo çææåæ®µé½åæå¯é
// Object.assign æ patch çåæ®µåå¹¶å° todo
// åªæ´æ°ä¼ äºçåæ®µï¼æ²¡ä¼ çä¸å
5.4 Partial<T> ç±»åæå·§
// Partial<T> æ¯ TypeScript å
ç½®çå·¥å
፱Ȍ
// ææ¥å£çææå±æ§åæå¯é
interface Todo {
id: number;
title: string;
complete: boolean;
}
type PartialTodo = Partial<Todo>;
// çä»·äºï¼
// {
// id?: number;
// title?: string;
// complete?: boolean;
// }
// PATCH è¯·æ±æ¶åªä¼ éè¦æ¹çåæ®µï¼
// PATCH /todos/1
// Body: { "complete": true }
// â patch = { complete: true }
// â Object.assign(todo, { complete: true })
// â åªæ¹ completeï¼id å title ä¸å
Object.assign åå¹¶åçï¼
const todo = { id: 1, title: 'å¦ä¹ ', complete: false };
const patch = { complete: true };
Object.assign(todo, patch);
â { id: 1, title: 'å¦ä¹ ', complete: true }
// patch 䏿çåæ®µè¦ç todo
// patch 䏿²¡æçåæ®µä¿æä¸å
注æï¼Object.assign æ¯æµ
æ·è´
妿 patch 䏿åµå¥å¯¹è±¡ï¼åªæ¯å¼ç¨å¤å¶
5.5 NotFoundExceptionï¼æ ååé误å¤ç
import { NotFoundException } from '@nestjs/common';
findOne(id: number): Todo {
const todo = todos.find(t => t.id === id);
if (!todo) throw new NotFoundException(`Todo ${id} ä¸åå¨`);
return todo;
}
NestJS å
ç½®é误类ä½ç³»ï¼
NotFoundException â 404 èµæºä¸åå¨
BadRequestException â 400 请æ±åæ°é误
UnauthorizedException â 401 æªè®¤è¯
ForbiddenException â 403 æ æé
ConflictException â 409 å²çªï¼å¦éå¤å建ï¼
InternalServerErrorException â 500 æå¡å¨å
é¨é误
throw new NotFoundException(`Todo ${id} ä¸åå¨`)
â NestJS æ¦æªå¼å¸¸ï¼èªå¨è½¬æ HTTP ååºï¼
{
"statusCode": 404,
"message": "Todo 5 ä¸åå¨",
"error": "Not Found"
}
对æ¯åç Node.jsï¼
â éè¦æå¨ res.status(404).json({ ... })
â NestJS èªå¨å¤çï¼å¼åè
åªé throw
â è¿å°±æ¯"æ ååé误è¾åº"
é误å¤ççæ¼è¿ï¼
åçæ¹å¼ï¼æå¨å¤çï¼ï¼
if (!todo) {
res.status(404).json({ statusCode: 404, message: 'ä¸åå¨' });
return;
}
NestJS æ¹å¼ï¼å¼å¸¸é©±å¨ï¼ï¼
if (!todo) throw new NotFoundException('ä¸åå¨');
â æ¡æ¶èªå¨è½¬æ 404 ååº
â ä»£ç æ´ç®æ´ï¼å
³æ³¨ä¸å¡é»è¾èéååºæ ¼å¼
ä¼ ç» try/catch/finallyï¼
â æ¯ä¸ªæ¹æ³é½è¦å try/catch
â 容æéæ¼ï¼çº¿ç¨ææ
â NestJS ç¨å¼å¸¸è¿æ»¤å¨ç»ä¸æ¦æª
â å¼åè
åªé throwï¼æ¡æ¶è´è´£å
åº
å ãtype importï¼TypeScript çå¯¼å ¥ä¼å
6.1 åºåç±»åå¯¼å ¥åå¼å¯¼å ¥
// Todos.controller.ts ä¸ç导å
¥
import { TodosService } from './Todos.service'; // å¼å¯¼å
¥
import type { Todo } from './Todos.service'; // ç±»å导å
¥
为ä»ä¹è¦åå¼ï¼
// TodosService æ¯ä¸ä¸ªç±»ï¼è¿è¡æ¶åå¨ï¼
import { TodosService } from './Todos.service';
// â éè¦å¨è¿è¡æ¶å建å®ä¾ãä¾èµæ³¨å
¥
// â å¿
é¡»å¼å¯¼å
¥
// Todo æ¯ä¸ä¸ªæ¥å£ï¼ç¼è¯æ¶åå¨ï¼è¿è¡æ¶æ¶å¤±ï¼
import type { Todo } from './Todos.service';
// â åªç¨äº TypeScript ç±»åæ æ³¨
// â ç¼è¯åä¼è¢«å®å
¨ç§»é¤
// â ä¸äº§çè¿è¡æ¶ä»£ç ï¼åå°æå
ä½ç§¯
ç¼è¯åï¼
import { TodosService } from './Todos.service';
import type { Todo } from './Todos.service';
findAll(): Todo[] {
return this.todosService.findAll();
}
ç¼è¯åï¼JavaScriptï¼ï¼
import { TodosService } from './Todos.service';
// import type { Todo } â å®å
¨æ¶å¤±ï¼
findAll() {
return this.todosService.findAll();
}
// Todo[] ç±»åæ æ³¨ä¹æ¶å¤±äº
6.2 type å¯¼å ¥çä¸ç§åæ³
// åæ³ä¸ï¼ç¬ç« type importï¼æ¨èï¼è¯ä¹ææ¸
æ°ï¼
import type { Todo } from './Todos.service';
// åæ³äºï¼å
è type 修饰符ï¼TS 4.5+ï¼
import { TodosService, type Todo } from './Todos.service';
// åæ³ä¸ï¼ä¸åºåï¼ç¼è¯å¨èªå¨å¤æï¼ä½ä¸æ¨èï¼
import { TodosService, Todo } from './Todos.service';
// â Todo å®é
æ¯ interfaceï¼ç¼è¯å¨ä¼èªå¨ç§»é¤
// â ä½ä¸å¤æ¾å¼ï¼å¯è½å½±å tree-shaking
ä¸ã宿´è¯·æ±-ååºæµç¨
7.1 端å°ç«¯æ°æ®æµ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 宿´è¯·æ±-ååºæµç¨ â
â â
â â æµè§å¨åèµ· HTTP è¯·æ± â
â GET http://localhost:3000/todos/1 â
â â
â â¡ NestJS è·¯ç±å¹é
â
â â @Controller('todos') åç¼å¹é
/todos â
â â @Get(':id') æ¹æ³å¹é
/todos/1 â
â â æåè·¯å¾åæ° id = '1' â
â â
â â¢ åæ°è£
饰卿§è¡ â
â @Param('id') id: string â id = '1' â
â â URL åæ°æ°¸è¿æ¯ string ç±»å â
â â
â ⣠Controller æ¹æ³æ§è¡ â
â findOne('1') â
â â Number('1') â 1 â
â â this.todosService.findOne(1) â
â â
â ⤠Service ä¸å¡é»è¾ â
â todos.find(t => t.id === 1) â
â â æ¾å° { id: 1, title: 'å¦ä¹ NestJS', complete: false } â
â â è¿å todo 对象 â
â â
â 妿æ¾ä¸å°ï¼ â
â â throw new NotFoundException('Todo 1 ä¸åå¨') â
â â NestJS å¼å¸¸è¿æ»¤å¨æ¦æª â
â â èªå¨è¿å 404 ååº â
â â
â ⥠Controller è¿åååº â
â â return todo â
â â NestJS èªå¨åºåå为 JSON â
â â HTTP 200 + JSON body â
â â
â ⦠æµè§å¨æ¶å°ååº â
â 200 OK â
â { "id": 1, "title": "å¦ä¹ NestJS", "complete": false } â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
7.2 äºä¸ªæ¥å£ç请æ±ä¸ååº
â è·åææ
GET /todos
â 200 OK
â [
{ "id": 1, "title": "å¦ä¹ NestJS", "complete": false },
{ "id": 2, "title": "å¦ä¹ CRUD", "complete": true }
]
â¡ è·åå个
GET /todos/1
â 200 OK
â { "id": 1, "title": "å¦ä¹ NestJS", "complete": false }
GET /todos/999
â 404 Not Found
â { "statusCode": 404, "message": "Todo 999 ä¸åå¨", "error": "Not Found" }
⢠å建
POST /todos
Body: { "title": "å¦ä¹ è£
饰å¨" }
â 201 Created
â { "id": 3, "title": "å¦ä¹ è£
饰å¨", "complete": false }
⣠å é¤
DELETE /todos/1
â 200 OK
â { "message": "success" }
DELETE /todos/999
â 404 Not Found
â { "statusCode": 404, "message": "Todo 999 ä¸åå¨", "error": "Not Found" }
⤠é¨åæ´æ°
PATCH /todos/1
Body: { "complete": true }
â 200 OK
â { "id": 1, "title": "å¦ä¹ NestJS", "complete": true }
å «ãNestJS è£ é¥°å¨å ¨æ¯å¾
8.1 ä¸å¤§æ ¸å¿è£ 饰å¨
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â NestJS ä¸å¤§æ ¸å¿è£
é¥°å¨ â
â â
â ç±»è£
饰å¨ï¼ä¿®é¥°æ´ä¸ªç±»ï¼ â
â âââ @Controller('todos') â 设置路ç±åç¼ï¼æ 记为æ§å¶å¨ â
â âââ @Module({ ... }) â ç»ç»æ¨¡åç»æ â
â âââ @Injectable() â 声ææå¡å¯è¢«ä¾èµæ³¨å
¥ â
â â
â æ¹æ³è£
饰å¨ï¼ä¿®é¥°ç±»çæ¹æ³ï¼ â
â âââ @Get() â GET è·¯ç± â
â âââ @Post() â POST è·¯ç± â
â âââ @Patch(':id') â PATCH è·¯ç± â
â âââ @Delete(':id') â DELETE è·¯ç± â
â â
â åæ°è£
饰å¨ï¼ä¿®é¥°æ¹æ³åæ°ï¼ â
â âââ @Param('id') â ä» URL è·¯å¾æååæ° â
â âââ @Body() / @Body('title') â ä»è¯·æ±ä½æåæ°æ® â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
8.2 è£ é¥°å¨å¨åå±çåå¸
Controller å±ä½¿ç¨çè£
饰å¨ï¼
@Controller('todos') â ç±»è£
饰å¨ï¼è·¯ç±åç¼
@Get() / @Post() / ... â æ¹æ³è£
饰å¨ï¼HTTP è·¯ç±
@Param('id') â åæ°è£
饰å¨ï¼è·¯å¾åæ°
@Body() / @Body('title') â åæ°è£
饰å¨ï¼è¯·æ±ä½
constructor(private readonly todosService: TodosService) â ä¾èµæ³¨å
¥
Service å±ä½¿ç¨çè£
饰å¨ï¼
@Injectable() â ç±»è£
饰å¨ï¼å¯æ³¨å
¥
Module å±ä½¿ç¨çè£
饰å¨ï¼
@Module({ imports, controllers, providers }) â ç±»è£
饰å¨ï¼æ¨¡åç»è£
ä¹ãNestJS å屿¶ææ»ç»
9.1 ä¸å±è责边ç
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â NestJS ä¸å±æ¶æ â
â â
â ââââââââââââââââââââââââââââââââââââââââ â
â â Module å±ï¼ç»è£
å±ï¼ â â
â â âââ @Module è£
é¥°å¨ â â
â â âââ imports: 忍¡åä¾èµ â â
â â âââ controllers: æ³¨åæ§å¶å¨ â â
â â âââ providers: 注åæå¡ â â
â â èè´£ï¼ç»è£
ï¼ä¸åä¸å¡é»è¾ â â
â ââââââââââââââââ¬ââââââââââââââââââââââââ â
â â â
â ââââââââââââââââ¼ââââââââââââââââââââââââ â
â â Controller å±ï¼æ§å¶å±ï¼ â â
â â âââ @Controller + @Get/@Post/... â â
â â âââ @Param + @Body åæ°æå â â
â â âââ åæ°æ ¡éª â â
â â âââ è°ç¨ Service â â
â â âââ return ååº â â
â â èè´£ï¼è·¯ç± + åæ°æ ¡éªï¼ä¸åä¸å¡é»è¾ â â
â ââââââââââââââââ¬ââââââââââââââââââââââââ â
â â â
â ââââââââââââââââ¼ââââââââââââââââââââââââ â
â â Service å±ï¼ä¸å¡å±ï¼ â â
â â âââ @Injectable 坿³¨å
¥ â â
â â âââ ä¸å¡é»è¾å¤ç â â
â â âââ æ°æ® CRUD â â
â â âââ é误å¤çï¼throw NotFoundExceptionï¼â â
â â âââ return æ°æ® â â
â â èè´£ï¼ææä¸å¡é»è¾é½å¨è¿é â â
â ââââââââââââââââââââââââââââââââââââââââ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
9.2 åå±"ä¸å"ä»ä¹
Module ä¸åï¼
â ä¸åä¸å¡é»è¾
â ä¸å¤ç HTTP 请æ±
â 䏿使°æ®åº
Controller ä¸åï¼
â ä¸ç´æ¥æä½æ°æ®åº
â ä¸å夿ä¸å¡é»è¾
â ä¸åæ°æ®å¤çä¸è½¬æ¢
Service ä¸åï¼
â ä¸å¤ç HTTP è·¯ç±ï¼ä¸å
³å¿ URL æ¯ä»ä¹ï¼
â ä¸è§£æè¯·æ±åæ°ï¼åæ°å·²è¢« Controller æåï¼
â 䏿 ¼å¼å HTTP ååºï¼è¿åçº¯æ°æ®ï¼NestJS èªå¨åºååï¼
åãæ»ç»
10.1 ç¥è¯ä½ç³»å¾
NestJS CRUD æ¥å£å·¥ç¨
â
âââ æ¨¡ååå¼åæµç¨
â âââ AppModule imports æ¤å
¥å模å
â âââ ä¸å¡æ¨¡å = Module + Controller + Service
â âââ @Module({ controllers, pro
Aitishiku.com