跳到主要内容

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)​

状态码含义使用场景
200OK成功处理请求
201Created资源创建成功
204No Content成功但无返回内容
202Accepted异步任务已接受

重定向(3xx)​

状态码含义使用场景
301Moved Permanently资源永久移动
304Not Modified资源未修改(缓存)

客户端错误(4xx)​

状态码含义使用场景
400Bad Request请求格式错误
401Unauthorized未认证
403Forbidden无权限
404Not Found资源不存在
405Method Not Allowed方法不允许
409Conflict资源冲突
422Unprocessable Entity验证失败
429Too Many Requests请求频率超限

服务器错误(5xx)​

状态码含义使用场景
500Internal Server Error服务器内部错误
502Bad Gateway网关错误
503Service Unavailable服务不可用
504Gateway 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"
}
}

认证方式​

方式格式适用场景
API KeyX-API-Key: <key>服务间通信、公开API
Basic AuthAuthorization: Basic <base64>简单场景(需HTTPS)
Bearer TokenAuthorization: Bearer <token>现代应用首选
OAuth 2.0授权码流程第三方授权、单点登录

JWT结构:Header.Payload.Signature

// Payload示例
{
"sub": "1234567890", // 用户ID
"name": "张三",
"role": "admin",
"iat": 1516239022, // 签发时间
"exp": 1516242622 // 过期时间
}

Token刷新流程:

Access Token过期 → 使用Refresh Token → 获取新的Access Token
(有效期长,存储安全)

版本控制策略​

策略格式优点缺点
URL路径/api/v1/users简单直观URL较长
查询参数/api/users?version=1URL简洁容易忽略
自定义头X-API-Version: 1URL干净调试不便
Accept头Accept: application/vnd.api.v1+json最RESTful实现复杂

语义化版本:MAJOR.MINOR.PATCH

  • MAJOR:不兼容的API变更
  • MINOR:向后兼容的功能新增
  • PATCH:向后兼容的问题修复

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
}
}
}
}

Apollo Client 缓存策略​

策略说明
cache-first优先缓存,不存在才请求网络(默认)
cache-only只使用缓存
network-only只请求网络
no-cache请求网络但不缓存
cache-and-network先返回缓存,同时请求网络更新

常用Hook:

// 查询
const { loading, error, data, refetch } = useQuery(GET_USER, {
variables: { id: '123' },
fetchPolicy: 'cache-first'
});

// 变更
const [createUser, { loading, error }] = useMutation(CREATE_USER, {
onCompleted: (data) => console.log(data)
});

// 懒查询
const [search, { data }] = useLazyQuery(SEARCH_QUERY);

// 订阅
const { data } = useSubscription(ON_MESSAGE);

REST vs GraphQL 对比​

特性RESTGraphQL
端点多个端点单一端点 /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平台