Skip to content

GraphQL - 类型系统

GraphQL 强大的类型系统(Type System)是其核心特性。它定义了 API 的能力,确保可预测性,支持强大的开发者工具,并能尽早捕获错误。每个 GraphQL 服务都会定义一套类型,它们完整地描述了你可以查询该服务的可能数据集合。

GraphQL 类型大致可分为:

  • 标量类型(Scalar Types): 表示原始的叶子值。
  • 对象类型(Object Types): 表示带有字段的结构化数据。
  • 输入对象类型(Input Object Types): 用作 mutation/query 参数的特殊对象。
  • 枚举类型(Enum Types): 表示一组固定的可能字符串值。
  • 接口类型(Interface Types): 定义一个契约,实现该契约的对象类型必须包含这些字段。
  • 联合类型(Union Types): 表示一个值可以是多种不同对象类型中的一个。
  • 根操作类型(Root Operation Types): Query、Mutation、Subscription,定义 API 入口点。

标量表示单个、不可分割的值。GraphQL 提供了内置的默认标量类型:

  • Int: 一个有符号 32 位整数。
  • Float: 一个有符号双精度浮点值。
  • String: 一个 UTF‐8 字符序列。
  • Boolean: true 或 false。
  • ID: 表示一个唯一的标识符,常用于获取对象或作为缓存的键。序列化后是 String 类型,但不旨在供人类阅读。

如果内置标量不足以满足需求,你还可以定义**自定义标量类型(Custom Scalar Types)**来表示特定数据格式(例如 Date、JSON、UUID)。这需要定义模式声明以及服务器端的序列化、反序列化和验证逻辑。

# Custom scalar declaration
scalar Date # 自定义标量声明
type Product {
id: ID!
name: String!
price: Float
inStock: Boolean
releaseDate: Date # Using custom scalar
}

对象类型是 GraphQL 中最常见的类型。它们表示一个由命名**字段(Fields)**组成的集合,其中每个字段都有自己的类型(可以是标量、枚举或其他对象类型,允许嵌套)。

# Object Type Definition
type Student {
id: ID!
firstName: String!
lastName: String
age: Int
college: College # Field linking to another Object type
}

Query 类型是一种特殊的对象类型,它定义了你的 API 上所有可能的读取操作入口点。每个 GraphQL 服务都必须有一个 Query 类型,尽管它可能是空的。

# Query Type Definition
type Query {
greeting: String # Simple query returning a scalar
students: [Student] # Query returning a list of Student objects
studentById(id: ID!): Student # Query taking an argument, returning one Student
}

类似于 Query,Mutation 类型是一种特殊的对象类型,它定义了写入操作(创建、更新、删除)的入口点。

# Mutation Type Definition
input CreateStudentInput { # Often use Input Objects for mutation args
firstName: String!
collegeId: ID!
}
type Mutation {
createStudent(input: CreateStudentInput!): Student # Creates a student, returns the new student
deleteStudent(id: ID!): Boolean # Deletes a student, returns success status
}

Subscription 类型定义了与服务器建立实时连接的入口点,允许客户端在特定事件发生时接收服务器推送的更新。

# Subscription Type Definition (Conceptual)
type Subscription {
newNotification(userId: ID!): Notification # Subscribe to notifications for a user
postUpdated(postId: ID!): Post # Subscribe to updates for a specific post
}

枚举类型将字段的值限制在一组预定义的允许字符串值之一。对于表示类别、状态等很有用。

# Enum Definition
enum CourseLevel {
BEGINNER
INTERMEDIATE
ADVANCED
}
type Course {
id: ID!
title: String!
level: CourseLevel # Field using the Enum type
}

你可以通过将类型包裹在方括号 [] 中来声明某个字段将返回特定类型的列表(数组)。

# List Type Usage
type Query {
studentNames: [String] # Returns a list of strings
allCourses: [Course] # Returns a list of Course objects
}

默认情况下,GraphQL 中的任何字段都可以返回 null。为了保证一个字段总是返回值(如果无法返回则触发错误),你在类型后附加一个感叹号 !。这也适用于参数。

# Non-Nullable Usage
type User {
id: ID! # ID will never be null
username: String! # Username will never be null
bio: String # Bio can be null (optional)
}
type Query {
userById(id: ID!): User # id argument is required, return type can be null
searchUsers(term: String!): [User!]! # Requires term, returns a non-null list
# where each User in the list is also non-null
}

理解组合用法:

  • String:可以是字符串或 null。
  • String!:必须是字符串,不能为 null。
  • [String]:可以是字符串列表、空列表或 null。
  • [String]!:必须是字符串列表或空列表,列表本身不能为 null。列表内的项可以为 null。
  • [String!]:可以是非空字符串列表、空列表或 null。列表本身可以为 null。
  • [String!]!:必须是列表(不能为 null),且列表内的每个项都必须是非空字符串。

接口(Interfaces): 定义实现该契约的对象类型必须遵循的字段集合。对于当不同类型共享共同字段时实现多态性(polymorphism)很有用(例如,由 Human 和 Droid 实现的 Character 接口)。

联合(Unions): 定义一个类型,它可以解析为几种不同对象类型中的一个,这些类型不一定共享字段。对于返回混合搜索结果很有用(例如,SearchResult 可以是 User、Post 或 Comment)。

这些抽象类型为建模复杂领域增加了更多灵活性,并且在查询(使用 ... on TypeName 片段 Fragment)和解析器(使用 __resolveType)中需要特殊处理。