1 Nestjs 写get post put delete 接口
NestJS 实战:CRUD 四个接口
一、整体认知:NestJS 的三层分工
写一个接口涉及三个角色: 请求进来 → Controller(接收请求、返回响应) ↓ 调用 Service(写业务逻辑) ↓ 操作 数据(数据库/数组)
- Controller:只管"接"和"回",不写逻辑
- Service:逻辑都写这里,通过依赖注入给 Controller 用
- DTO:定义请求体的形状(等价于 FastAPI 里的 Pydantic 模型)
二、完整代码:用户管理 CRUD
1. DTO(数据校验)—— src/users/dto/user.dto.ts
TypeScript
import { IsString, IsInt, Min, Max, IsOptional } from 'class-validator';
// 创建用户时的请求体
export class CreateUserDto {
@IsString()
name: string;
@IsInt()
@Min(1)
@Max(150)
age: number;
}
// 更新用户时(字段都可选,改哪个传哪个)
export class UpdateUserDto {
@IsOptional()
@IsString()
name?: string;
@IsOptional()
@IsInt()
age?: number;
}
需要
npm install class-validator class-transformer,并在main.ts里开启全局校验:TypeScript
app.useGlobalPipes(new ValidationPipe());
2. Service(业务逻辑)—— src/users/users.service.ts
TypeScript
import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateUserDto, UpdateUserDto } from './dto/user.dto';
interface User {
id: number;
name: string;
age: number;
}
@Injectable()
export class UsersService {
// 先用内存数组模拟数据库(学到 TypeORM/Prisma 再换真的)
private users: User[] = [
{ id: 1, name: '张三', age: 25 },
{ id: 2, name: '李四', age: 30 },
];
private nextId = 3;
findAll(): User[] {
return this.users;
}
findOne(id: number): User {
const user = this.users.find((u) => u.id === id);
if (!user) {
throw new NotFoundException(`用户 ${id} 不存在`); // 自动返回 404
}
return user;
}
create(dto: CreateUserDto): User {
const user: User = { id: this.nextId++, ...dto };
this.users.push(user);
return user;
}
update(id: number, dto: UpdateUserDto): User {
const user = this.findOne(id); // 复用,找不到会自动抛 404
Object.assign(user, dto);
return user;
}
remove(id: number): void {
const user = this.findOne(id);
this.users = this.users.filter((u) => u.id !== user.id);
}
}
3. Controller(路由层)—— src/users/users.controller.ts
TypeScript
import {
Controller, Get, Post, Put, Delete,
Param, Body, ParseIntPipe,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto, UpdateUserDto } from './dto/user.dto';
@Controller('users') // 所有路由都以 /users 开头
export class UsersController {
// 依赖注入:NestJS 自动把 Service 实例塞进来
constructor(private readonly usersService: UsersService) {}
@Get() // GET /users → 查全部
findAll() {
return this.usersService.findAll();
}
@Get(':id') // GET /users/1 → 查单个
findOne(@Param('id', ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
@Post() // POST /users → 新增
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
@Put(':id') // PUT /users/1 → 更新
update(
@Param('id', ParseIntPipe) id: number,
@Body() dto: UpdateUserDto,
) {
return this.usersService.update(id, dto);
}
@Delete(':id') // DELETE /users/1 → 删除
remove(@Param('id', ParseIntPipe) id: number) {
this.usersService.remove(id);
return { message: `用户 ${id} 已删除` };
}
}
4. 注册到 Module —— src/users/users.module.ts
TypeScript
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
然后在 app.module.ts 的 imports 数组里加上 UsersModule,启动:
powershell
npm run start:dev
三、测试(PowerShell 里用 curl 验证)
powershell
# 查全部
curl http://localhost:3000/users
# 新增
curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d '{"name":"王五","age":28}'
# 更新
curl -X PUT http://localhost:3000/users/1 -H "Content-Type: application/json" -d '{"age":26}'
# 删除
curl -X DELETE http://localhost:3000/users/1
试试故意传错数据(比如 age 传 200),会被 DTO 校验拦住,自动返回 400——这就是 class-validator 的价值。
四、和 FastAPI 对照(提前建立直觉)
表格
| 概念 | NestJS | FastAPI(第 06 章会学) |
|---|---|---|
| 路由声明 | @Get(':id') 装饰器 | @app.get("/{id}") 装饰器 |
| 路径参数 | @Param('id', ParseIntPipe) | id: int(自动转换) |
| 请求体校验 | DTO + class-validator | Pydantic 模型 |
| 依赖注入 | constructor(private service) | Depends() |
| 业务分层 | Controller / Service | Router / Service |
五、自测作业
在刚才的代码基础上加一个接口,不许看答案先自己写:
GET /users/search?keyword=张 —— 按名字模糊搜索用户(提示:用
@Query('keyword')接收参数,filter+includes过滤)