REST 与 GraphQL 速查表
REST API 速查
HTTP方法
| 方法 | 用途 | 幂等 | 安全 | 示例 |
|---|---|---|---|---|
| GET | 获取资源 | ✓ | ✓ | GET /users/123 |
| POST | 创建资源 | ✗ | ✗ | POST /users |
| PUT | 完整更新 | ✓ | ✗ | PUT /users/123 |
| PATCH | 部分更新 | ✗ | ✗ | PATCH /users/123 |
| DELETE | 删除资源 | ✓ | ✗ | DELETE /users/123 |
HTTP状态码
成功响应(2xx)
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 200 | OK | 成功处理请求 |
| 201 | Created | 资源创建成功 |
| 204 | No Content | 成功但无返回内容 |
| 202 | Accepted | 异步任务已接受 |
重定向(3xx)
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 301 | Moved Permanently | 资源永久移动 |
| 304 | Not Modified | 资源未修改(缓存) |
客户端错误(4xx)
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 400 | Bad Request | 请求格式错误 |
| 401 | Unauthorized | 未认证 |
| 403 | Forbidden | 无权限 |
| 404 | Not Found | 资源不存在 |
| 405 | Method Not Allowed | 方法不允许 |
| 409 | Conflict | 资源冲突 |
| 422 | Unprocessable Entity | 验证失败 |
| 429 | Too Many Requests | 请求频率超限 |
服务器错误(5xx)
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 500 | Internal Server Error | 服务器内部错误 |
| 502 | Bad Gateway | 网关错误 |
| 503 | Service Unavailable | 服务不可用 |
| 504 | Gateway Timeout | 网关超时 |
URL设计规范
正确示例:
GET /users 获取用户列表
GET /users/123 获取单个用户
GET /users/123/articles 获取用户的文章
POST /users 创建用户
PUT /users/123 更新用户
DELETE /users/123 删除用户
查询参数:
GET /articles?status=published&author=123
GET /articles?page=1&limit=20
GET /articles?sort=createdAt&order=desc
错误示例:
/getUsers ❌ URL中不应包含动词
/user ❌ 应使用复数形式
/Users/123 ❌ 应使用小写
/users/123/ ❌ 不应有尾部斜杠
请求头
Content-Type: application/json
Accept: application/json
Authorization: Bearer <token>
Cache-Control: no-cache
If-None-Match: "<etag>"
If-Modified-Since: <date>
响应头
Content-Type: application/json
Cache-Control: max-age=3600
ETag: "<etag>"
Last-Modified: <date>
Location: /users/124
X-Request-Id: <uuid>
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
分页响应格式
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
},
"links": {
"first": "/articles?page=1",
"prev": null,
"next": "/articles?page=2",
"last": "/articles?page=5"
}
}
错误响应格式
{
"error": {
"code": "VALIDATION_ERROR",
"message": "请求参数验证失败",
"details": [
{
"field": "email",
"message": "邮箱格式不正确"
}
],
"requestId": "req-abc123"
}
}
GraphQL 速查
类型系统
scalar Int
scalar Float
scalar String
scalar Boolean
scalar ID
type User {
id: ID!
name: String!
email: String!
age: Int
isActive: Boolean!
articles: [Article!]!
}
enum Status {
DRAFT
PUBLISHED
ARCHIVED
}
interface Node {
id: ID!
}
union SearchResult = User | Article
input CreateUserInput {
name: String!
email: String!
}
操作类型
type Query {
user(id: ID!): User
users(limit: Int, offset: Int): [User!]!
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User
deleteUser(id: ID!): Boolean!
}
type Subscription {
onUserCreated: User!
onArticleUpdated(id: ID): Article!
}
查询语法
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
articles(limit: 5) {
id
title
}
}
}
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
}
}
subscription OnCommentAdded($articleId: ID!) {
onCommentAdded(articleId: $articleId) {
id
content
}
}
变量
query GetUser($id: ID!, $withEmail: Boolean = true) {
user(id: $id) {
name
email @include(if: $withEmail)
}
}
{
"id": "123",
"withEmail": false
}
片段
fragment UserFields on User {
id
name
email
}
query {
user(id: "123") {
...UserFields
articles {
title
}
}
}
指令
query GetArticles($withContent: Boolean!) {
articles {
id
title
content @include(if: $withContent)
author @skip(if: true) {
name
}
}
}
| 指令 | 作用 |
|---|---|
| @include(if: Boolean) | 条件为true时包含字段 |
| @skip(if: Boolean) | 条件为true时跳过字段 |
| @deprecated(reason: String) | 标记字段已废弃 |
别名
query {
me: user(id: "123") {
name
}
friend: user(id: "456") {
name
}
publishedArticles: articles(status: PUBLISHED) {
title
}
draftArticles: articles(status: DRAFT) {
title
}
}
内联片段
query Search($keyword: String!) {
search(keyword: $keyword) {
... on User {
id
name
}
... on Article {
id
title
}
}
}
分页(Relay规范)
query {
articles(first: 10, after: "cursor") {
edges {
node {
id
title
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
totalCount
}
}
内省查询
query {
__schema {
types {
name
}
}
__type(name: "User") {
name
fields {
name
type {
name
}
}
}
}
REST vs GraphQL 对比
| 特性 | REST | GraphQL |
|---|---|---|
| 端点 | 多个端点 | 单一端点 /graphql |
| 数据获取 | 固定响应结构 | 客户端指定字段 |
| 过度获取 | 可能发生 | 不会发生 |
| 获取不足 | 可能需要多次请求 | 一次请求完成 |
| 类型系统 | 无内置 | 强类型Schema |
| 缓存 | HTTP缓存原生支持 | 需要额外实现 |
| 学习曲线 | 相对简单 | 需要学习查询语言 |
| 版本控制 | URL版本控制 | 无版本演进 |
| 工具支持 | 广泛 | 丰富生态 |
| 调试 | 简单(浏览器直接访问) | 需要专门工具 |
选择建议
选择REST的场景
- 公开API,需要广泛兼容性
- 资源模型清晰,CRUD操作为主
- 需要利用HTTP缓存机制
- 团队对REST更熟悉
- 简单的数据模型
选择GraphQL的场景
- 数据关系复杂
- 前端需要精确控制数据获取
- 需要聚合多个数据源
- 需要强类型系统支持
- 内部API,团队可以统一技术栈
- 移动端应用,需要减少请求次数
常用工具
REST工具
- Postman - API测试工具
- curl - 命令行HTTP客户端
- Swagger/OpenAPI - API文档规范
- Insomnia - API测试工具
GraphQL工具
- Apollo Server - GraphQL服务器
- Apollo Client - GraphQL客户端
- GraphiQL - GraphQL IDE
- GraphQL Playground - GraphQL IDE
- Altair - GraphQL客户端
- Apollo Studio - GraphQL平台