Chapter 02

Schema 定义语言(SDL)

掌握 GraphQL 类型系统——API 的核心契约

SDL 基础

什么是 SDL?

Schema Definition Language(SDL)是 GraphQL 的类型系统描述语言。它定义了 API 中所有可用的数据类型和操作。SDL 是语言无关的——无论你用 JavaScript、Python 还是 Go 实现 GraphQL 服务器,SDL 的语法都是一样的。

基本类型定义

# 对象类型(Object Type):GraphQL 中最常用的类型
type User {
  id: ID!           # ! 表示 Non-null,不能为 null
  name: String!
  email: String!
  age: Int           # 可以为 null(可选字段)
  posts: [Post!]!   # 非空数组,每个元素也非空
  createdAt: String
}

type Post {
  id: ID!
  title: String!
  content: String
  author: User!     # 关联到 User 类型
  tags: [String!]   # 可空数组,但元素非空
  published: Boolean!
}

内置标量类型

String
UTF-8 字符串。JSON 中的字符串值。
Int
32 位有符号整数,范围 -2,147,483,648 到 2,147,483,647。
Float
IEEE 754 双精度浮点数。
Boolean
true 或 false。
ID
唯一标识符,序列化为字符串。可以是数字 ID 或 UUID,但总以字符串形式传输。

自定义标量类型

# 声明自定义标量
scalar Date
scalar DateTime
scalar JSON
scalar Upload    # 文件上传
scalar URL
scalar Email

# 在类型中使用
type Event {
  id: ID!
  name: String!
  startDate: DateTime!
  metadata: JSON    # 任意 JSON 数据
  imageUrl: URL
}
// 自定义标量的服务器实现(graphql-scalars 库)
import { DateTimeResolver, JSONResolver } from 'graphql-scalars';

const resolvers = {
  DateTime: DateTimeResolver,  // 自动处理序列化/反序列化
  JSON: JSONResolver,
  // 或自定义实现
  Date: new GraphQLScalarType({
    name: 'Date',
    description: 'Date custom scalar type',
    serialize(value) { return (value as Date).toISOString().split('T')[0]; },
    parseValue(value) { return new Date(value as string); },
    parseLiteral(ast) {
      if (ast.kind === Kind.STRING) return new Date(ast.value);
      return null;
    },
  }),
};

枚举类型(enum)

enum UserRole {
  ADMIN
  EDITOR
  VIEWER
}

enum OrderStatus {
  PENDING
  PROCESSING
  SHIPPED
  DELIVERED
  CANCELLED
}

type User {
  id: ID!
  name: String!
  role: UserRole!
}

type Order {
  id: ID!
  status: OrderStatus!
  items: [OrderItem!]!
}

Input 类型

Input 类型专门用于 mutation 和 query 的参数,不能包含其他 Object type(只能是标量、enum 或其他 input)。

input CreateUserInput {
  name: String!
  email: String!
  password: String!
  role: UserRole = VIEWER  # 有默认值
}

input UpdateUserInput {
  name: String        # 所有字段可选(用于部分更新)
  email: String
  role: UserRole
}

input PaginationInput {
  page: Int = 1
  pageSize: Int = 20
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
}

Union 与 Interface

Interface:共同字段的抽象

interface Node {
  id: ID!
}

interface Timestamps {
  createdAt: DateTime!
  updatedAt: DateTime!
}

# 类型实现接口
type User implements Node & Timestamps {
  id: ID!
  name: String!
  createdAt: DateTime!
  updatedAt: DateTime!
}

# 查询接口类型(使用内联片段)
query {
  node(id: "u1") {
    id
    ... on User {
      name
      email
    }
    ... on Post {
      title
    }
  }
}

Union:完全不同类型的集合

# SearchResult 可以是 User、Post 或 Product 中的任意一种
union SearchResult = User | Post | Product

type Query {
  search(term: String!): [SearchResult!]!
}

# 查询 union 类型必须用内联片段
query {
  search(term: "Alice") {
    __typename  # 内置字段,返回类型名
    ... on User { name email }
    ... on Post { title author { name } }
    ... on Product { name price }
  }
}

根类型:Query、Mutation、Subscription

# Schema 的三个根类型
type Query {
  user(id: ID!): User
  users(pagination: PaginationInput): [User!]!
  post(id: ID!): Post
  search(term: String!): [SearchResult!]!
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!
}

type Subscription {
  userCreated: User!
  postPublished(authorId: ID): Post!
}

# 显式声明 Schema(可选,默认用 Query/Mutation/Subscription 作为名称)
schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

Schema 设计原则

Schema 设计最佳实践