NestJS RESTful API 示例:订单管理
下面是一个完整的 NestJS RESTful API 示例,实现一个订单管理系统(包括 CRUD 操作),涵盖最佳实践如 DTO 验证、服务层逻辑、异常处理和 Swagger 文档。2. DTO 数据传输对象创建订单 DTO ():更新订单 DTO ():3. 服务层 ()4. 控制器 ()5. 模块定义 ()6. 启用 Swagger 文档 ()响应获取所有订单更新订单删除订单关键特性演示DT
下面是一个完整的 NestJS RESTful API 示例,实现一个订单管理系统(包括 CRUD 操作),涵盖最佳实践如 DTO 验证、服务层逻辑、异常处理和 Swagger 文档。

项目结构
src/
├── order/
│ ├── dto/
│ │ ├── create-order.dto.ts # 创建订单的验证规则
│ │ ├── update-order.dto.ts # 更新订单的验证规则
│ │ └── order-response.dto.ts # 统一响应格式
│ ├── entities/
│ │ └── order.entity.ts # 订单实体类
│ ├── order.controller.ts # 控制器(路由定义)
│ ├── order.service.ts # 服务层(业务逻辑)
│ └── order.module.ts # 模块定义
├── app.module.ts # 根模块
└── main.ts # 入口文件(启用Swagger)

代码实现
1. 订单实体 (order.entity.ts)
export class Order {
id: number;
productName: string;
quantity: number;
price: number;
status: 'PENDING' | 'SHIPPED' | 'DELIVERED'; // 订单状态枚举
createdAt: Date;
}
2. DTO 数据传输对象
创建订单 DTO (create-order.dto.ts):
import { IsString, IsInt, Min, IsEnum } from 'class-validator';
export class CreateOrderDto {
@IsString()
productName: string;
@IsInt()
@Min(1)
quantity: number;
@IsInt()
@Min(0)
price: number;
@IsEnum(['PENDING', 'SHIPPED'])
status: 'PENDING' | 'SHIPPED';
}
更新订单 DTO (update-order.dto.ts):
import { PartialType } from '@nestjs/mapped-types';
import { CreateOrderDto } from './create-order.dto';
// 继承CreateOrderDto并设为可选
export class UpdateOrderDto extends PartialType(CreateOrderDto) {}
3. 服务层 (order.service.ts)
import { Injectable, NotFoundException } from '@nestjs/common';
import { Order } from './entities/order.entity';
import { CreateOrderDto, UpdateOrderDto } from './dto';
@Injectable()
export class OrderService {
private orders: Order[] = []; // 模拟数据库
private nextId = 1;
// 创建订单
create(createOrderDto: CreateOrderDto): Order {
const newOrder: Order = {
id: this.nextId++,
...createOrderDto,
status: createOrderDto.status || 'PENDING',
createdAt: new Date(),
};
this.orders.push(newOrder);
return newOrder;
}
// 查找所有订单
findAll(): Order[] {
return this.orders;
}
// 查找单个订单
findOne(id: number): Order {
const order = this.orders.find(o => o.id === id);
if (!order) throw new NotFoundException(`Order #${id} not found`);
return order;
}
// 更新订单
update(id: number, updateOrderDto: UpdateOrderDto): Order {
const order = this.findOne(id);
Object.assign(order, updateOrderDto);
return order;
}
// 删除订单
remove(id: number): void {
const index = this.orders.findIndex(o => o.id === id);
if (index === -1) throw new NotFoundException(`Order #${id} not found`);
this.orders.splice(index, 1);
}
}
4. 控制器 (order.controller.ts)
import {
Controller,
Get,
Post,
Put,
Delete,
Param,
Body,
HttpCode,
HttpStatus,
} from '@nestjs/common';
import { OrderService } from './order.service';
import { CreateOrderDto, UpdateOrderDto } from './dto';
import { Order } from './entities/order.entity';
@Controller('orders') // 基础路径 /orders
export class OrderController {
constructor(private readonly orderService: OrderService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createOrderDto: CreateOrderDto): Order {
return this.orderService.create(createOrderDto);
}
@Get()
findAll(): Order[] {
return this.orderService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): Order {
return this.orderService.findOne(+id); // 转换为数字
}
@Put(':id')
update(
@Param('id') id: string,
@Body() updateOrderDto: UpdateOrderDto,
): Order {
return this.orderService.update(+id, updateOrderDto);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string): void {
this.orderService.remove(+id);
}
}
5. 模块定义 (order.module.ts)
import { Module } from '@nestjs/common';
import { OrderController } from './order.controller';
import { OrderService } from './order.service';
@Module({
controllers: [OrderController],
providers: [OrderService],
})
export class OrderModule {}
6. 启用 Swagger 文档 (main.ts)
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 配置Swagger
const config = new DocumentBuilder()
.setTitle('Order Management API')
.setDescription('The NestJS Order API description')
.setVersion('1.0')
.addTag('orders')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document); // 访问 /api 查看文档
await app.listen(3000);
}
bootstrap();

测试 API(使用 curl)
创建订单
curl -X POST http://localhost:3000/orders \
-H "Content-Type: application/json" \
-d '{
"productName": "Laptop",
"quantity": 2,
"price": 1200,
"status": "PENDING"
}'
响应
{
"id": 1,
"productName": "Laptop",
"quantity": 2,
"price": 1200,
"status": "PENDING",
"createdAt": "2023-10-05T08:30:00.000Z"
}
获取所有订单
curl http://localhost:3000/orders
更新订单
curl -X PUT http://localhost:3000/orders/1 \
-H "Content-Type: application/json" \
-d '{"status": "SHIPPED"}'
删除订单
curl -X DELETE http://localhost:3000/orders/1
关键特性演示
-
DTO 验证
如果请求缺少必填字段(如price),自动返回400 Bad Request:{ "statusCode": 400, "message": ["price must be a positive number"], "error": "Bad Request" } -
异常处理
访问不存在的订单 ID 时返回404 Not Found:{ "statusCode": 404, "message": "Order #99 not found", "error": "Not Found" } -
Swagger 文档
访问http://localhost:3000/api查看交互式文档:
!https://miro.medium.com/v2/resize:fit:1400/1*5J6zWlVvYqQfXqj_9y6x3g.png
进阶优化建议
-
数据库集成
替换内存存储为 TypeORM/Prisma:// 使用TypeORM实体 @Entity() export class OrderEntity { @PrimaryGeneratedColumn() id: number; @Column() productName: string; // ... } -
分页查询
在服务层添加分页参数:findAll(page = 1, limit = 10) { return this.orders.slice((page - 1) * limit, page * limit); } -
身份验证
添加 JWT 守卫保护敏感操作:@UseGuards(JwtAuthGuard) @Delete(':id') remove(@Param('id') id: string) { ... }
这个示例展示了 NestJS 的核心优势:清晰的代码结构、强类型验证、可扩展性和开发者友好的工具链。实际项目中可根据需求扩展功能(如数据库、缓存、消息队列)。
RESTful API
RESTful API 是一种基于 REST(Representational State Transfer,表述性状态转移)架构风格 设计的 API,核心思想是通过 资源(Resource) 为中心,利用 HTTP 协议的标准方法(GET/POST/PUT/DELETE 等)实现对资源的操作,具有简洁、可扩展、松耦合的特点。以下是其基础知识体系:

一、REST 的核心约束(6大原则)
REST 架构定义了 6 条约束(其中第 6 条为可选),满足这些约束的 API 才能称为“RESTful”:
| 约束 | 含义 |
|---|---|
| 1. 客户端-服务器分离 | 客户端(如浏览器、App)负责用户界面,服务器负责数据存储和业务逻辑,两者独立演化。 |
| 2. 无状态(Stateless) | 服务器不存储客户端上下文(如会话信息),每次请求必须包含所有必要信息(如认证令牌),简化服务器设计。 |
| 3. 可缓存(Cacheable) | 响应需明确是否可缓存(通过 Cache-Control 头),减少重复请求,提升性能。 |
| 4. 统一接口(Uniform Interface) | 客户端与服务器通过标准化的接口通信,核心包括: - 资源通过 URI 唯一标识; - 通过 HTTP 方法操作资源; - 资源表述自包含(如 JSON/XML); - HATEOAS(超媒体驱动,见下文)。 |
| 5. 分层系统(Layered System) | 架构可分为多层(如负载均衡层、应用层、数据层),每层仅与相邻层交互,隐藏内部实现。 |
| 6. 按需代码(Code on Demand,可选) | 服务器可向客户端临时发送可执行代码(如 JavaScript),扩展客户端功能(较少使用)。 |
二、RESTful API 的关键特征
1. 资源导向(Resource-Oriented)
-
资源:API 操作的核心对象(如用户、订单、商品),用 URI(统一资源标识符) 唯一标识。
-
URI 设计原则:
- 用 名词复数 表示资源集合(如
/users表示用户列表,/orders表示订单列表); - 用 嵌套 URI 表示资源关系(如
/users/123/orders表示 ID=123 用户的订单); - 避免动词(如不用
/getUsers,而用 GET/users); - 小写字母+连字符分隔(如
/user-profiles,不用驼峰)。
✅ 正确示例:
GET /orders/456(获取 ID=456 的订单)、POST /products(创建商品)。
❌ 错误示例:GET /getOrder?id=456(含动词)、POST /createProduct(冗余动词)。 - 用 名词复数 表示资源集合(如
2. HTTP 方法映射 CRUD 操作
RESTful API 严格遵循 HTTP 方法的语义,对应资源的 增删改查(CRUD):
| HTTP 方法 | 语义 | 操作 | 示例 URI | 响应状态码 |
|---|---|---|---|---|
| GET | 获取资源(幂等) | 查询单个/多个资源 | GET /orders(所有订单)GET /orders/1(ID=1 的订单) |
200 OK(成功) 404 Not Found(资源不存在) |
| POST | 创建资源(非幂等) | 新增资源(服务器生成 ID) | POST /orders(创建订单) |
201 Created(成功创建) 400 Bad Request(参数错误) |
| PUT | 全量更新资源(幂等) | 替换整个资源(需提供完整字段) | PUT /orders/1(更新 ID=1 的订单,全量替换) |
200 OK(成功) 404 Not Found(资源不存在) |
| PATCH | 部分更新资源(非幂等) | 仅修改部分字段(如只改状态) | PATCH /orders/1(更新 ID=1 的订单状态) |
200 OK(成功) |
| DELETE | 删除资源(幂等) | 删除指定资源 | DELETE /orders/1(删除 ID=1 的订单) |
204 No Content(成功删除,无响应体) |
- 幂等性:多次执行同一请求,结果相同(如 GET/PUT/DELETE 是幂等的,POST 不是)。
3. 状态码(Status Code)
用 HTTP 标准状态码表示请求结果,避免自定义错误码:
| 类别 | 状态码 | 含义 | 示例场景 |
|---|---|---|---|
| 2xx 成功 | 200 OK | 请求成功(GET/PUT/PATCH) | 获取订单列表、更新订单成功 |
| 201 Created | 资源创建成功(POST) | 创建订单后返回新订单 ID | |
| 204 No Content | 成功但无响应体(DELETE) | 删除订单后返回空响应 | |
| 4xx 客户端错误 | 400 Bad Request | 请求参数错误(如格式不对) | 创建订单时 price 为负数 |
| 401 Unauthorized | 未认证(如 token 无效) | 未登录用户访问需认证的接口 | |
| 403 Forbidden | 已认证但无权限 | 普通用户尝试删除他人订单 | |
| 404 Not Found | 资源不存在 | 访问 /orders/999(ID=999 的订单不存在) |
|
| 409 Conflict | 资源冲突(如重复创建) | 创建已存在的用户名 | |
| 5xx 服务器错误 | 500 Internal Server Error | 服务器内部错误(如代码 bug) | 数据库连接失败 |
4. 数据格式与表述
- 表述(Representation):资源的具体形式(如 JSON、XML),最常用 JSON(轻量、易读)。
- 请求/响应头:
Content-Type: application/json:表示请求体/响应体是 JSON 格式;Accept: application/json:客户端希望接收 JSON 格式响应。
- 示例响应体(JSON):
{ "id": 1, "productName": "Laptop", "quantity": 2, "price": 1200, "status": "PENDING", "createdAt": "2023-10-05T08:30:00Z", "_links": { // HATEOAS 链接(可选) "self": { "href": "/orders/1" }, "update": { "href": "/orders/1", "method": "PUT" } } }
5. HATEOAS(超媒体作为应用状态的引擎)
REST 的高级特性:响应中不仅包含数据,还包含 超媒体链接,引导客户端下一步操作(类似网页的“超链接”)。
- 例如,获取订单列表时,响应中可包含“创建订单”“查看订单详情”的链接,客户端无需硬编码 URI。
- 目前多数 API 未完全实现,但体现了 REST 的“自描述”思想。
6. 版本控制
API 迭代时需保证旧版本兼容,常见版本控制方式:
- URI 版本:
/v1/orders、/v2/orders(直观,最常用); - 请求头版本:
Accept: application/vnd.company.v1+json(通过Accept头指定版本); - 查询参数版本:
/orders?version=1(不推荐,破坏 URI 纯净性)。
三、RESTful API 最佳实践
- 使用 HTTPS:加密传输数据,避免明文暴露。
- 合理分页/过滤:对大数据集用
?page=1&limit=10分页,?status=PENDING过滤。 - 统一错误处理:用标准 JSON 格式返回错误(如
{ "code": "ORDER_NOT_FOUND", "message": "订单不存在" })。 - 认证与授权:用 JWT/OAuth2 等机制,通过
Authorization: Bearer <token>头传递凭证。 - 避免过度设计:小型 API 无需严格遵循所有约束(如 HATEOAS),优先保证简洁可用。
四、RESTful API vs 其他 API 风格
| 对比项 | RESTful API | GraphQL | SOAP |
|---|---|---|---|
| 核心思想 | 资源导向,HTTP 方法语义 | 按需获取数据(单一端点) | XML 协议,强类型契约(WSDL) |
| 灵活性 | 固定端点,多请求获取关联数据 | 单端点,客户端自定义查询字段 | 严格契约,灵活性低 |
| 性能 | 可能产生冗余数据(Over-fetching) | 精确获取数据(Under-fetching) | 较重(XML 冗余),性能较差 |
| 适用场景 | 简单 CRUD、通用后端 API | 复杂前端需求(如动态表单) | 企业级系统集成(银行、政府) |
五、总结
RESTful API 的核心是 “资源为中心 + HTTP 语义标准化”,通过简洁的 URI、明确的 HTTP 方法和状态码,实现客户端与服务器的松耦合通信。其优势在于 易理解、易扩展、兼容性好,是现代 Web 开发中最主流的 API 设计风格(如 GitHub API、Twitter API 均采用 RESTful 设计)。
结合前文 NestJS 示例,其控制器(@Controller('/orders'))和 HTTP 方法装饰器(@Get/@Post 等)正是 RESTful 思想的落地实现,通过模块化分层进一步强化了 API 的可维护性。
更多推荐
所有评论(0)