编 程 实 战

记录编程学习之路,分享技术实践经验

API

RESTful API 设计最佳实践

2026-07-04 · 阅读 1,720 · 作者 编程实战

REST(Representational State Transfer)是目前最主流的 API 设计风格。 一个好的 RESTful API 设计能让前后端协作更加顺畅,降低沟通成本和维护难度。 本文将系统介绍 RESTful API 的设计原则与最佳实践。

资源命名规范

REST 的核心思想是把一切视为资源。URL 应该表示资源,而非操作:

# ✅ 好的设计:名词复数 + 层级关系
GET    /api/v1/articles           # 文章列表
GET    /api/v1/articles/123      # 单篇文章
POST   /api/v1/articles           # 创建文章
PUT    /api/v1/articles/123      # 更新文章(全量)
PATCH  /api/v1/articles/123      # 更新文章(部分)
DELETE /api/v1/articles/123      # 删除文章

# 子资源
GET    /api/v1/articles/123/comments       # 文章下的评论
GET    /api/v1/articles/123/comments/45    # 特定评论

# ❌ 避免的设计
GET /api/v1/getArticles         # 动词
GET /api/v1/article_list        # 下划线
POST /api/v1/createArticle      # 动词

HTTP 方法与语义

方法语义幂等安全
GET获取资源
POST创建资源
PUT全量更新
PATCH部分更新
DELETE删除资源

HTTP 状态码

# 2xx — 成功
200 OK              # 请求成功(GET、PUT、PATCH)
201 Created         # 创建成功(POST)
204 No Content      # 删除成功,无响应体

# 3xx — 重定向
301 Moved Permanently  # 资源永久迁移
304 Not Modified       # 缓存有效

# 4xx — 客户端错误
400 Bad Request     # 请求参数有误
401 Unauthorized    # 未认证
403 Forbidden       # 无权限
404 Not Found       # 资源不存在
409 Conflict        # 资源冲突
422 Unprocessable   # 语义错误(参数校验失败)
429 Too Many Requests  # 被限流

# 5xx — 服务端错误
500 Internal Server Error  # 服务端内部错误
502 Bad Gateway            # 网关错误
503 Service Unavailable    # 服务不可用

分页、过滤与排序

# 分页(推荐游标分页,避免 offset 在大数据量下的性能问题)
GET /api/v1/articles?cursor=123&limit=20

# 传统页码分页
GET /api/v1/articles?page=2&page_size=20

# 过滤
GET /api/v1/articles?status=published&category=backend

# 排序
GET /api/v1/articles?sort=-created_at,+title  # - 表示降序

# 字段选择(减少传输量)
GET /api/v1/articles?fields=id,title,created_at

统一响应格式

// 成功响应
{
    "code": 0,
    "message": "success",
    "data": {
        "id": 123,
        "title": "RESTful API 设计",
        "created_at": "2026-07-04T10:30:00Z"
    }
}

// 列表响应
{
    "code": 0,
    "message": "success",
    "data": {
        "items": [...],
        "total": 100,
        "next_cursor": "abc123"
    }
}

// 错误响应
{
    "code": 40401,
    "message": "文章不存在",
    "details": {
        "resource": "article",
        "id": "999"
    }
}

版本控制

# 推荐:URL 路径版本(简单直观)
/api/v1/articles
/api/v2/articles

# 备选:请求头版本(URL 更干净,但调试不便)
GET /api/articles
Accept: application/vnd.myapp.v2+json

# 版本更新原则:
# - 新增字段:不需要升版本,向后兼容
# - 删除/重命名字段:需要新版本
# - 改变字段语义:需要新版本

认证与安全

# JWT 认证
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...

# API 限流响应头
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1699000000

# CORS 配置(仅信任可信域名)
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE

HATEOAS:让 API 自描述

// 在响应中包含相关操作的链接
{
    "id": 123,
    "title": "RESTful API 设计",
    "status": "draft",
    "_links": {
        "self": { "href": "/api/v1/articles/123" },
        "comments": { "href": "/api/v1/articles/123/comments" },
        "publish": { "href": "/api/v1/articles/123/publish", "method": "POST" },
        "author": { "href": "/api/v1/users/42" }
    }
}

实战:用 FastAPI 实现 RESTful API

from fastapi import FastAPI, Query, Path, HTTPException
from pydantic import BaseModel
from typing import Optional

app = FastAPI(title="Blog API", version="1.0.0")

class ArticleCreate(BaseModel):
    title: str
    content: str
    category: str

class ArticleResponse(BaseModel):
    id: int
    title: str
    content: str
    category: str
    created_at: str

@app.get("/api/v1/articles", response_model=list[ArticleResponse])
async def list_articles(
    category: Optional[str] = None,
    cursor: Optional[int] = None,
    limit: int = Query(default=20, le=100)
):
    # 查询逻辑
    return []

@app.post("/api/v1/articles", status_code=201)
async def create_article(body: ArticleCreate):
    # 创建逻辑
    return {"id": 123, **body.dict()}

@app.get("/api/v1/articles/{article_id}")
async def get_article(
    article_id: int = Path(ge=1)
):
    # 查询逻辑
    raise HTTPException(status_code=404, detail="文章不存在")

总结

好的 API 设计遵循一致性原则,让调用方能够"猜"到下一个接口的用法。 核心要点:资源命名用名词复数、正确使用 HTTP 方法和状态码、 提供统一响应格式和分页机制、做好版本控制和认证。 RESTful API 不是银弹——对于实时通信等场景,可能需要结合 WebSocket 或 GraphQL。

← 返回首页