Skip to content

GraphQL - 简介

GraphQL 是一种开源的查询语言(query language),用于你的 API,也是一个服务器端运行时环境(server-side runtime),用于通过你现有数据执行这些查询。GraphQL 由 Facebook 于 2012 年内部开发,并于 2015 年公开发布,它提供了一种比传统 REST API 更高效、强大且灵活的替代方案。

GraphQL 没有定义多个返回固定数据结构(就像在 REST 中那样)的僵化端点(endpoint),而是暴露一个单一的端点,允许客户端精确地请求他们需要的数据,不多不少。

为何选择 GraphQL?相比 REST 的关键优势

Section titled “为何选择 GraphQL?相比 REST 的关键优势”

虽然 REST API 一直以来表现良好,但它们经常带来挑战,特别是在数据需求不断变化的复杂应用中。GraphQL 解决了其中的许多问题:

1. 按需索取,不多不少(避免过度获取 - Over-fetching)

Section titled “1. 按需索取,不多不少(避免过度获取 - Over-fetching)”

REST 中的问题: 典型的 REST 端点(例如,/api/users/123)可能会返回一个包含许多字段的大型用户对象,即使客户端只需要用户的姓名和电子邮件。这称为过度获取(over-fetching)—— 下载了不必要的数据,浪费了带宽并可能降低应用速度。

GraphQL 解决方案: 客户端发送一个查询,精确指定他们想要的字段。服务器只响应那些数据。

考虑获取学生的 ID 和名字:

# GraphQL Query
query GetStudentName {
student(id: "S1001") {
id
firstName
}
}

响应将只包含 id 和 firstName,即使底层的 Student 类型有许多其他字段(如 lastName、collegeName 等)。

// GraphQL Response
{
"data": {
"student": {
"id": "S1001",
"firstName": "Mohtashim"
}
}
}

这使得应用更快、更高效,特别是在移动网络上。

2. 一次请求获取多个资源(避免数据不足获取 - Under-fetching)

Section titled “2. 一次请求获取多个资源(避免数据不足获取 - Under-fetching)”

REST 中的问题: 为了获取相关数据(例如,用户及其帖子,或学生及其大学详情),客户端通常需要对不同端点进行多次往返请求(例如,先请求 /api/users/123,然后请求 /api/users/123/posts)。这称为数据不足获取(under-fetching)—— 单个端点提供的数据不足,导致多次网络请求和增加延迟(即“N+1 问题”)。

GraphQL 解决方案: GraphQL 查询可以在一次请求中遍历相关的对象图。客户端可以高效地获取复杂的对象关系图。

获取学生的详细信息及其关联的大学信息:

# GraphQL Query
query GetStudentAndCollege {
student(id: "S1001") {
id
firstName
lastName
college { # Traverse to the related college object 遍历到相关的大学对象
name
location
}
}
}

响应会一次性包含所有请求的嵌套数据:

// GraphQL Response
{
"data": {
"student": {
"id": "S1001",
"firstName": "Mohtashim",
"lastName": "Mohammad",
"college": {
"name": "CUSAT",
"location": "Kerala"
}
}
}
}

这大大减少了客户端所需的网络请求数量。

GraphQL API 是强类型的。 服务器使用 GraphQL Schema Definition Language (SDL) 定义一个 schema(模式),指定所有可用的数据类型、字段、查询(query)和变更(mutation)。这个类型系统充当客户端和服务器之间的契约。

  • 可预测的结果: 客户端确切知道预期的数据类型。
  • 早期错误检测: 无效的查询(请求不存在的字段、错误的参数类型)在执行前由服务器捕获。
  • 改进的开发者体验: 支持强大的开发者工具。
  • 内省(Introspection): 客户端可以查询 schema 本身以了解 API 的能力(例如,哪些查询可用,一个对象有哪些字段)。这允许自动生成文档和客户端代码。

Schema 示例片段:

type Student {
id: ID! # ID is a specific scalar type, ! means non-nullable ID 是一种特定的标量类型,! 表示不可为空
firstName: String
lastName: String
college: College # Field linking to another object type 链接到另一个对象类型的字段
}
type College {
id: ID!
name: String!
location: String
}
type Query {
student(id: ID!): Student # Query to fetch a student by ID 按 ID 获取学生的查询
students: [Student] # Query to fetch a list of students 获取学生列表的查询
}

REST 中的问题: 从 REST 端点添加或删除字段通常需要进行版本控制(例如,/api/v1/users,/api/v2/users)以避免破坏现有客户端。

GraphQL 解决方案: 由于客户端指定他们需要的确切字段,可以在不影响现有客户端的情况下向 schema 添加新字段(它们只是不会请求新字段)。可以在 schema 中标记已废弃(deprecated)的字段,给客户端在删除之前迁移的时间。

  • Schema: 定义 API 能力的蓝图。
  • Queries: 读取操作,用于获取数据。
  • Mutations: 写入操作,用于创建、更新或删除数据。
  • Subscriptions: 实时操作,接收由服务器推送的数据更新(通常通过 WebSockets)。
  • Types: 在 schema 中定义的数据结构(Scalars、Objects、Enums 等)。
  • Resolvers: 服务器端函数,为 schema 字段提供数据。

本教程将引导你学习这些概念,让你能够有效地构建和使用 GraphQL API。