API 响应格式规范
核心原则
API 响应必须使用统一的格式,遵循 Ant Design Pro 响应规范,确保前后端数据交互的一致性。
允许的做法
成功响应(单条数据)
- 使用
success: true表示成功 - 使用
data字段包含响应数据
json
{
"success": true,
"data": {
"id": 123,
"name": "Alice",
"email": "alice@example.com",
"createdAt": 1704038400
}
}go
// ✅ 正确 - Go 实现
type BaseResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
}
func Success(data interface{}) BaseResponse {
return BaseResponse{
Success: true,
Data: data,
}
}
// Handler 中使用
func GetUser(c echo.Context) error {
user, _ := userService.GetByID(id)
return c.JSON(http.StatusOK, response.Success(user))
}成功响应(列表数据/分页)
- 使用
success: true - 使用
data数组包含列表数据 - 使用
total、current、pageSize表示分页信息
json
{
"success": true,
"data": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
],
"total": 100,
"current": 1,
"pageSize": 20
}go
// ✅ 正确 - Go 实现
type PagedResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Total int64 `json:"total,omitempty"`
Current int `json:"current,omitempty"`
PageSize int `json:"pageSize,omitempty"`
}
func SuccessPaged(data interface{}, total int64, current, pageSize int) PagedResponse {
return PagedResponse{
Success: true,
Data: data,
Total: total,
Current: current,
PageSize: pageSize,
}
}
// Handler 中使用
func ListUsers(c echo.Context) error {
users, total, _ := userService.List(page, pageSize)
return c.JSON(http.StatusOK, response.SuccessPaged(users, total, page, pageSize))
}失败响应
- 使用
success: false - 使用
errorMessage说明错误原因 - 使用
errorCode标识错误类型
json
{
"success": false,
"errorMessage": "用户不存在",
"errorCode": 1002
}go
// ✅ 正确 - Go 实现
type ErrorResponse struct {
Success bool `json:"success"`
ErrorMessage string `json:"errorMessage,omitempty"`
ErrorCode int `json:"errorCode,omitempty"`
}
func Fail(errorCode int, errorMessage string) ErrorResponse {
return ErrorResponse{
Success: false,
ErrorMessage: errorMessage,
ErrorCode: errorCode,
}
}
// Handler 中使用
func GetUser(c echo.Context) error {
user, err := userService.GetByID(id)
if err != nil {
return c.JSON(http.StatusNotFound, response.Fail(1002, "用户不存在"))
}
return c.JSON(http.StatusOK, response.Success(user))
}字段校验错误响应
字段校验失败时,返回详细的字段错误信息:
json
{
"success": false,
"errorMessage": "参数校验失败",
"errorCode": 1001,
"errors": [
{ "field": "email", "message": "邮箱格式不正确" },
{ "field": "password", "message": "密码长度至少8位" }
]
}go
// ✅ 正确 - 字段校验错误响应
type ValidationErrorResponse struct {
Success bool `json:"success"`
ErrorMessage string `json:"errorMessage,omitempty"`
ErrorCode int `json:"errorCode,omitempty"`
Errors []ValidationError `json:"errors,omitempty"`
}
type ValidationError struct {
Field string `json:"field"`
Message string `json:"message"`
}
func FailWithValidation(errorCode int, errorMessage string, errors []ValidationError) ValidationErrorResponse {
return ValidationErrorResponse{
Success: false,
ErrorMessage: errorMessage,
ErrorCode: errorCode,
Errors: errors,
}
}
// Handler 中使用
func (h *UserHandler) Create(c echo.Context) error {
var req CreateUserRequest
if err := c.Bind(&req); err != nil {
return c.JSON(400, response.Fail(1000, "参数格式错误"))
}
if err := c.Validate(&req); err != nil {
return c.JSON(400, response.FailWithValidation(1001, "参数校验失败", []response.ValidationError{
{Field: "email", Message: "邮箱格式不正确"},
{Field: "password", Message: "密码长度至少8位"},
}))
}
// 创建用户逻辑...
}删除操作响应
- 使用
success: true - 可选 返回空 data 或不返回 data
json
{
"success": true
}go
// ✅ 正确 - Go 实现
func DeleteUser(c echo.Context) error {
err := userService.Delete(id)
if err != nil {
return c.JSON(http.StatusInternalServerError, response.Fail(500, "删除失败"))
}
return c.JSON(http.StatusOK, response.Success(nil))
}禁止的做法
禁止的响应格式
- 禁止 直接返回数据(不包装)
- 禁止 返回不一致的结构
- 禁止 在成功响应中包含 error 字段
json
❌ 错误 - 直接返回数据
{
"id": 123,
"name": "Alice"
}
❌ 错误 - 不一致的结构
{
"code": 200,
"message": "success",
"result": {...}
}
❌ 错误 - 成功响应包含 error
{
"success": true,
"data": {...},
"error": null
}完整响应示例
创建资源
POST /api/v1/users
Request:
{
"name": "Alice",
"email": "alice@example.com"
}
Response (201 Created):
{
"success": true,
"data": {
"id": 123,
"name": "Alice",
"email": "alice@example.com",
"createdAt": 1704038400
}
}更新资源
PATCH /api/v1/users/123
Request:
{
"name": "Alice Wang"
}
Response (200 OK):
{
"success": true,
"data": {
"id": 123,
"name": "Alice Wang",
"email": "alice@example.com",
"updatedAt": 1704038500
}
}获取列表(分页)
GET /api/v1/users?page=1&pageSize=20
Response (200 OK):
{
"success": true,
"data": [
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob", "email": "bob@example.com" }
],
"total": 100,
"current": 1,
"pageSize": 20
}参数验证错误
POST /api/v1/users
Request:
{
"name": "",
"email": "invalid-email"
}
Response (400 Bad Request):
{
"success": false,
"errorMessage": "参数验证失败:邮箱格式不正确",
"errorCode": 1000
}资源不存在
GET /api/v1/users/999
Response (404 Not Found):
{
"success": false,
"errorMessage": "用户不存在",
"errorCode": 1001
}服务器错误
GET /api/v1/users
Response (500 Internal Server Error):
{
"success": false,
"errorMessage": "服务器内部错误",
"errorCode": 500
}特殊场景
批量操作响应
json
{
"success": true,
"data": {
"successCount": 8,
"failCount": 2,
"failed": [
{ "id": 3, "reason": "用户不存在" },
{ "id": 7, "reason": "无权限删除" }
]
}
}文件上传响应
json
{
"success": true,
"data": {
"url": "https://cdn.example.com/files/abc123.jpg",
"filename": "avatar.jpg",
"size": 102400
}
}TypeScript 类型定义
响应类型
typescript
// ✅ 正确 - TypeScript 类型定义
export interface BaseResponse<T = any> {
success: boolean;
data?: T;
}
export interface ErrorResponse {
success: false;
errorMessage: string;
errorCode: number;
}
export interface ValidationErrorResponse extends ErrorResponse {
errors?: Array<{
field: string;
message: string;
}>;
}
export interface PagedResponse<T = any> {
success: boolean;
data?: T[];
total?: number;
current?: number;
pageSize?: number;
}
// 联合类型:响应可能成功或失败
export type APIResponse<T = any> = BaseResponse<T> | ErrorResponse | ValidationErrorResponse;前端使用示例
typescript
// ✅ 正确 - 前端请求处理
import { message } from 'antd';
import type { BaseResponse, ErrorResponse } from '@/types/response';
// 示例 1:获取单条数据
async function getUser(id: number) {
const response = await request.get<BaseResponse<User>>(`/api/v1/users/${id}`);
if (!response.success) {
message.error(response.errorMessage || '请求失败');
return null;
}
return response.data;
}
// 示例 2:获取列表数据(分页)
async function getUserList(params: { current: number; pageSize: number }) {
const response = await request.get<PagedResponse<User>>('/api/v1/users', { params });
if (!response.success) {
message.error(response.errorMessage || '获取列表失败');
return { data: [], total: 0 };
}
return {
data: response.data || [],
total: response.total || 0,
};
}
// 示例 3:创建资源
async function createUser(data: CreateUserParams) {
const response = await request.post<BaseResponse<User>>('/api/v1/users', data);
if (!response.success) {
if ('errors' in response && response.errors) {
// 处理字段校验错误
response.errors.forEach(err => {
message.error(`${err.field}: ${err.message}`);
});
} else {
message.error(response.errorMessage || '创建失败');
}
return null;
}
message.success('创建成功');
return response.data;
}
// 示例 4:使用 ProTable
import type { ProColumns } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
const columns: ProColumns<User>[] = [
{ title: 'ID', dataIndex: 'id' },
{ title: '姓名', dataIndex: 'name' },
{ title: '邮箱', dataIndex: 'email' },
];
<ProTable<User>
columns={columns}
request={async (params) => {
const response = await request.get<PagedResponse<User>>('/api/v1/users', {
params: {
current: params.current,
pageSize: params.pageSize,
...params,
},
});
return {
data: response.data || [],
success: response.success,
total: response.total || 0,
};
}}
/>统一请求拦截器
typescript
// ✅ 正确 - 请求拦截器处理响应
import axios from 'axios';
import { message } from 'antd';
const request = axios.create({
baseURL: '/api/v1',
timeout: 10000,
});
// 响应拦截器
request.interceptors.response.use(
(response) => {
const data = response.data;
// 检查响应是否成功
if (data.success === false) {
// 处理字段校验错误
if (data.errors && Array.isArray(data.errors)) {
data.errors.forEach((err: any) => {
message.error(`${err.field}: ${err.message}`);
});
} else {
message.error(data.errorMessage || '请求失败');
}
return Promise.reject(data);
}
return data;
},
(error) => {
message.error('网络错误,请稍后重试');
return Promise.reject(error);
}
);
export default request;Go 实现完整示例
go
// backend/httpapi/response/response.go
package response
// BaseResponse 基础响应
type BaseResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
}
// ErrorResponse 错误响应
type ErrorResponse struct {
Success bool `json:"success"`
ErrorMessage string `json:"errorMessage,omitempty"`
ErrorCode int `json:"errorCode,omitempty"`
}
// PagedResponse 分页响应
type PagedResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Total int64 `json:"total,omitempty"`
Current int `json:"current,omitempty"`
PageSize int `json:"pageSize,omitempty"`
}
// Success 创建成功响应
func Success(data interface{}) BaseResponse {
return BaseResponse{Success: true, Data: data}
}
// Fail 创建失败响应
func Fail(errorCode int, errorMessage string) ErrorResponse {
return ErrorResponse{
Success: false,
ErrorMessage: errorMessage,
ErrorCode: errorCode,
}
}
// SuccessPaged 创建分页成功响应
func SuccessPaged(data interface{}, total int64, current, pageSize int) PagedResponse {
return PagedResponse{
Success: true,
Data: data,
Total: total,
Current: current,
PageSize: pageSize,
}
}相关文档
- RESTful 规范 - API 设计规范
- 错误码设计 - 错误码定义
- 后端开发规范 - 错误处理