AI Agent 开发学习路线-第五课

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

less 复制代码
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

arduino 复制代码
app.useGlobalPipes(new ValidationPipe());

2. Service(业务逻辑)------ src/users/users.service.ts

TypeScript

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

less 复制代码
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

python 复制代码
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.tsimports 数组里加上 UsersModule,启动:

powershell

arduino 复制代码
npm run start:dev

三、测试(PowerShell 里用 curl 验证)

powershell

bash 复制代码
# 查全部
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 过滤)

相关推荐
用户5619035069331 小时前
模型输出被截断、报 context length 超限怎么解决?
ai编程
tachibana22 小时前
什么是 Function Calling ?
数据库·人工智能·ai·llm·agent
全栈弄潮儿²⁰²⁴2 小时前
AI Agent 开发实战(7):如何接入搜索和数据库工具?
数据库·人工智能·ai·chatgpt·oracle·agent·ai编程
prog_61032 小时前
【笔记】用cursor手搓cursor(十)
人工智能·笔记·大语言模型·agent
云雀衔光2 小时前
MCP 协议全景:为什么它是 AI 连接工具的「USB-C」
java·开发语言·数据库·人工智能·ai编程
全栈弄潮儿2 小时前
我的 AI 编程工作台:工具、模型与基础配置
aigc·openai·ai编程
CHAM_GJ2 小时前
提交之间——当代码由对话生成,版本控制的对象变了
ai编程·双向可追溯·意图留存
徐龙2 小时前
给大模型装一双手:一个"能自己开 Chrome 把票买完"的 Agent,是怎么设计出来的
agent
Web3_Basketball2 小时前
多模态 RAG 图文混合检索实战:把日调用 10 亿次的 WeMM-Embedding 搬进自己项目
ai编程