跳到主要内容

5.1 DTO 与 API 契约

本章目标: 明确前后端通过 HTTP 和 JSON 协作,约定成功与失败的结构。

以实际 JSON 为准​

C# DTO
public record TaskDto(int Id, string Title, bool IsDone);
public record CreateTaskRequest(string Title);
public record UpdateTaskRequest(bool IsDone);

ASP.NET Core 使用默认 Web JSON 选项时,响应通常为:

{"id":1,"title":"学习 Vue","isDone":false}
TypeScript DTO
interface TaskItem { id: number; title: string; isDone: boolean; }
interface CreateTaskRequest { title: string; }
interface UpdateTaskRequest { isDone: boolean; }

前端读取 isDone,不能因为 C# 属性叫 IsDone 就照搬大小写。自定义 JSON 选项、JsonPropertyName 或第三方响应包装都可能改变契约。

先列出接口​

方法路径请求体成功结果
GET/api/tasks无200 + 任务数组
GET/api/tasks/{id}无200 + 单条任务,或 404
POST/api/tasks{ "title": "..." }201 + 新任务
PUT/api/tasks/{id}{ "isDone": true }200 + 更新后的任务
DELETE/api/tasks/{id}无204,无正文

本手册实战的 PUT 表示“设置完成状态”,DTO 特意只包含 isDone,不是通用任务编辑接口。生产项目可按团队约定改为 PATCH,但前后端必须一起调整。

记录不存在返回 404,输入无效返回 400。前端发送状态设置值,比“服务端收到一次就翻转一次”更容易处理重复提交。

统一错误格式​

ASP.NET Core 的 ProblemDetails / ValidationProblemDetails 能表达结构化错误,例如:

输入验证失败
{
"title": "One or more validation errors occurred.",
"status": 400,
"errors": { "title": ["任务名称不能为空"] }
}

前端优先展示字段 errors,其次 detail,再其次 title。最终保留 HTTP 状态码作为兜底。不要把数据库异常堆栈直接返回给用户。

Minimal API 与 Controller 校验不同

带 [ApiController] 的 Controller 常提供自动模型验证。Minimal API 是否自动执行 DataAnnotations 校验取决于 .NET 版本及配置。本手册示例显式校验标题,避免依赖隐含行为。

类型映射中的边界​

后端值JSON / 前端建议原因
int 正整数 IDnumber位于 JS 安全整数范围内
大 long IDstring大于 2^53 - 1 时可能丢精度
decimal 金额约定十进制字符串或最小单位整数JS number 是二进制浮点
DateTimeOffsetISO 8601 字符串不会自动变成 JS Date,需明确时区
枚举明确约定数字或字符串JSON 转换器设置会影响结果
可空属性T | null,按契约可能另有缺省null 与字段未返回不是完全一样

分页契约​

public record PageResult<T>(IReadOnlyList<T> Items, int Total, int Page, int PageSize);
interface PageResult<T> {
items: T[];
total: number;
page: number;
pageSize: number;
}

明确页码从 0 还是 1 开始,最大 pageSize,排序稳定性和空页行为。前端本地筛选当前页不能替代服务端对全部数据的筛选。

已使用 Furion 的项目​

Furion 可能按配置对响应进行统一包装。观察真实响应后决定是否在 API 模块拆出业务 data,别把本手册的“裸数组”写法直接用于所有 Furion 项目。

例如实际返回 { code, data, message } 时,应检查 HTTP 层和业务 code,再验证 data。统一处理放在 API 层,不让每个组件各猜一次返回格式。

练习​

在 Network 中记录实战项目 GET、POST、DELETE 的成功状态与正文。把 TaskItem.id 暂改为 string,观察编译器是否能自动验证服务器真的返回了字符串。

检查答案

成功状态分别为 200、201、204,DELETE 没有正文。只改 TS 类型不能改变后端 JSON,也不能生成运行时验证;需要实际请求检查和边界验证。

参考:ASP.NET Core 错误处理、System.Text.Json 命名规则。