Schema定义、Query查询、Mutation变更及GraphQL vs REST深度对比
GraphQL是Facebook于2015年开源的API查询语言和运行时,它提供了一种更灵活、更高效的数据获取方式。与REST不同,GraphQL让客户端能够精确指定需要的数据,避免了数据获取不足或过多的问题。如今,GraphQL已被GitHub、Shopify、Twitter等大型平台广泛采用。本指南将帮助你从零理解GraphQL的核心概念。
GraphQL不是一种数据库技术,也不是一种编程语言,而是一个API查询语言和运行时。它定义了一套类型系统,客户端可以用这个类型系统来精确请求所需的数据。
GraphQL的核心优势:
Schema是GraphQL API的核心,它定义了所有可用的数据类型、查询和变更操作。使用Schema Definition Language(SDL)编写。
# 定义类型
type User {
id: ID!
name: String!
email: String!
age: Int
posts: [Post!]!
createdAt: String!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
tags: [String!]!
likes: Int!
}
# 定义输入类型
type CreateUserInput {
name: String!
email: String!
age: Int
}
# 定义查询入口
type Query {
user(id: ID!): User
users(limit: Int, offset: Int): [User!]!
posts(userId: ID): [Post!]!
search(query: String!): [Post!]!
}
# 定义变更入口
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, name: String, email: String): User!
deleteUser(id: ID!): Boolean!
createPost(title: String!, content: String!): Post!
likePost(id: ID!): Post!
}
# 定义订阅入口
type Subscription {
newPost: Post!
userUpdated(id: ID!): User!
}
! 表示该字段非空(Non-Null)。[Post!]! 表示非空的Post数组,数组中每个元素也不能为null。
Query用于读取数据,是GraphQL最常用的操作类型。
# 基本查询
query {
user(id: "123") {
name
email
posts {
title
likes
}
}
}
# 带变量和参数
query GetUsers($limit: Int = 10) {
users(limit: $limit) {
id
name
email
}
}
# 使用别名(同类型字段多次查询)
query {
admin: users(role: "admin") {
id
name
}
editors: users(role: "editor") {
id
name
}
}
# 片段复用
query {
user(id: "123") {
...UserFields
posts {
...PostFields
}
}
}
fragment UserFields on User {
id
name
email
}
fragment PostFields on Post {
title
likes
createdAt
}
Mutation用于修改数据(创建、更新、删除)。按照惯例,Mutation按顺序执行(不同于Query的并行执行)。
# 创建用户
mutation {
createUser(input: {
name: "张三",
email: "zhangsan@example.com",
age: 28
}) {
id
name
email
}
}
# 同时执行多个变更
mutation UpdateUserAndPost($userId: ID!, $postId: ID!, $title: String!) {
updateUser(id: $userId, name: "李四") {
id
name
}
updatePost(id: $postId, title: $title) {
id
title
}
}
# 订阅新文章
subscription {
newPost {
id
title
author {
name
}
}
}
Subscription基于WebSocket实现,当服务端有新数据时自动推送给客户端。适用于实时通知、聊天应用、协作编辑等场景。
| 维度 | REST | GraphQL |
|---|---|---|
| 端点数量 | 多个(每个资源一个) | 单个(/graphql) |
| 数据获取 | 固定结构,可能过多或不足 | 客户端按需指定 |
| 关联数据 | 多次请求或over-fetching | 一次请求嵌套获取 |
| 版本控制 | URL路径版本(v1, v2) | 字段演进,无需版本号 |
| 类型安全 | 依赖文档或OpenAPI | 内置强类型系统 |
| 缓存 | HTTP缓存天然支持 | 需要额外配置 |
| 学习曲线 | 较低 | 中等 |
| 错误处理 | HTTP状态码 | 200 + errors字段 |
| 实时能力 | 需要SSE/WebSocket | 内置Subscription |
推荐使用GraphQL:数据模型复杂、多个客户端需要不同数据、需要实时功能、微服务聚合层。
推荐继续使用REST:简单CRUD应用、需要HTTP缓存、团队对REST更熟悉、带宽敏感的移动端场景。
访问 ToolSnap 获取JSON格式化、代码美化、编码转换等在线开发者工具。
REST有多个端点,每个端点返回固定结构;GraphQL只有一个端点,客户端可以精确指定需要的数据字段。REST可能需要多次请求获取关联数据,GraphQL一次请求即可获取所有需要的数据。
GraphQL适合:复杂嵌套数据结构、多客户端需要不同数据字段、实时数据订阅、微服务API网关聚合。不适合简单的CRUD应用或需要HTTP缓存优化的场景。
Schema是GraphQL的类型系统定义,描述了所有可用的数据类型、查询和变更操作。它是API的"合同",客户端和服务端通过Schema达成数据约定。
GraphQL请求始终返回200状态码,错误信息放在响应的errors字段中。每个错误包含message、locations、path等信息。