网站 API 集成基础指南:从 REST 到 GraphQL

一个内容站往往不是“一个程序”这么简单:页面要读文章列表,注册要提交表单,用户头像要上传,搜索要对接第三方……前端每做一次这类动作,背后都是一次 API 调用。API(应用程序接口)把这些数据交换约定成一套规矩,前端照着规矩请求,后端按规矩应答。这篇文章从 REST 讲到 GraphQL,帮你把网站前后端对接的基础打牢。

RESTful API 基础

REST(Representational State Transfer)是目前最流行的 API 设计风格,绝大多数公共接口——GitHub、Stripe、支付宝开放平台——都遵循它。它的核心是把一切业务对象当作“资源”,用 URL 定位、用 HTTP 方法表达动作。

核心原则

  • 资源导向:每个 URL 代表一个资源(/api/users/api/articles
  • HTTP 方法语义:GET 读取、POST 创建、PUT 更新、DELETE 删除
  • 无状态:每个请求包含完成它所需的全部信息,服务端不保存会话
  • 统一接口:一致的 URL 结构和响应格式,客户端无需特殊约定

设计示例

以文章模块为例,一套典型 REST 接口是这样组织的:

方法 端点 说明
GET /api/articles 获取文章列表(可带分页参数)
GET /api/articles/:id 获取单篇文章
POST /api/articles 创建文章
PUT /api/articles/:id 更新文章
DELETE /api/articles/:id 删除文章

响应通常用 JSON,并约定统一的返回结构,比如 { "code": 0, "data": [...], "message": "ok" }。状态码也要用对:200 成功、201 创建成功、400 参数错误、401 未登录、404 不存在、429 限流、500 服务端错误。前端拿到非 2xx 状态码时,应该统一进入错误分支,而不是盲目解析 body。

前端调用示例

// 使用 Fetch API 调用 REST 接口
async function getArticles() {
  const response = await fetch('/api/articles');
  if (!response.ok) throw new Error('Failed to fetch');
  return response.json();
}

// POST 请求
async function createArticle(data) {
  const response = await fetch('/api/articles', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data)
  });
  return response.json();
}

写前端调用时最容易漏的是两件事:一是错误处理fetch 只有在网络异常时才 reject,HTTP 4xx/5xx 并不会抛异常,所以要手动检查 response.ok;二是取消请求,用户快速切换页面时,用 AbortController 中止掉过期请求,避免旧响应覆盖新页面状态。更系统的设计规范可以看REST API 设计指南。

GraphQL 入门

GraphQL 是 Facebook 推出的查询语言,它把“后端定接口”改成“前端按需取数”:客户端在请求里声明要哪些字段,服务端只返回这些字段。对多端复用(Web + 移动端)和字段需求差异很大的页面,能明显减少冗余传输。

REST vs GraphQL

特性 REST GraphQL
数据获取 固定结构 客户端自定义
过度获取 常见 不会
多次请求 可能需要多次请求 单次请求
学习曲线
缓存 原生 HTTP 缓存 需要额外配置
工具生态 成熟 快速发展

GraphQL 查询示例

# 查询:只获取需要的数据
query {
  articles(first: 10) {
    id
    title
    author {
      name
    }
  }
}

# 变更:创建数据
mutation {
  createArticle(title: "Hello", content: "World") {
    id
    title
  }
}

怎么选:一个务实的判断

对大多数中小型网站,先 REST 后 GraphQL 是更稳的路线。判断依据很简单:

  • 页面多、字段需求差异大、有移动端复用 → GraphQL 的按需取数价值更高;
  • 团队小、接口简单、后端已有大量 REST 代码 → 继续用 REST,避免引入 schema 与解析层的维护成本;
  • 出现“一个页面要调 5 个接口才能拼齐数据”的情况,再考虑引入 GraphQL 聚合。

另外,无论选哪种方案,都要先约定好接口文档的维护方式:REST 用 OpenAPI/Swagger 描述,GraphQL 自带 introspection 能力。文档是前后端协作的地基,文档和实现不一致,联调期会浪费大量时间。

不管选哪套,接口都要做版本化/api/v2/...Accept 头),保证升级不破坏老客户端;鉴权、限流、日志这些横切能力,参考API 安全认证统一落地。后端工程实践可以看后端对接分类,例如Node.js API 示例;数据怎么存、怎么选型,见数据库选型。

常见问题

  • 接口返回慢怎么办:先看是不是 N+1 查询,再看是否缺索引,最后考虑 CDN 缓存和数据库缓存。
  • 要不要用 SDK:官方 SDK 封装了鉴权、重试和类型,小项目直接用 fetch 也完全够。
  • 跨域报错怎么排查:后端需返回正确的 Access-Control-Allow-Origin,需要携带 Cookie 时还要打开 credentials
  • 联调环境怎么区分:准备 devstagingprod 三套环境,前端用环境变量切换 baseURL,避免测试数据污染生产接口。

参考:REST 的更多最佳实践可阅读微软 Azure 架构中心的 Web API 设计文档 https://learn.microsoft.com/azure/architecture/best-practices/api-design;GraphQL 官方规范见 https://graphql.org/learn/

前端调用

// 使用 Apollo Client 调用 GraphQL
import { ApolloClient, gql } from '@apollo/client';

const client = new ApolloClient({
  uri: '/graphql',
});

const GET_ARTICLES = gql`
  query GetArticles {
    articles {
      id
      title
    }
  }
`;

const { data } = await client.query({ query: GET_ARTICLES });

API 安全最佳实践

身份认证

// JWT Token 认证
const response = await fetch('/api/protected', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

速率限制

API 端点应配置速率限制(Rate Limiting),防止滥用。

输入验证

所有 API 输入必须在服务端进行验证。

字段 验证规则
email 有效邮箱格式
title 1-200 字符
content 1-50000 字符
file 限制大小和类型

16IDC 观察

对于大多数中小型网站,RESTful API 是最实用、最容易上手的选择。GraphQL 适合数据结构复杂、需要灵活数据获取的场景。建议新项目从 REST 开始,当出现「过度获取」或「多次请求」问题时再考虑引入 GraphQL。