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 设计最佳实践
- 以客户端为中心设计:Schema 应该反映客户端的数据需求,而不是数据库表结构
- 使用 Non-null 明确约束:字段确定不会为 null 时加
!,这帮助客户端做类型推断 - ID 字段用 ID 类型:不要用 String 或 Int 表示标识符
- Mutation 使用 input 类型:将参数包装在 input 类型中,便于版本演进
- 返回变更后的数据:Mutation 应返回被修改的对象,避免客户端额外查询
- 分页使用 Connection 模式:遵循 Relay Connection 规范,支持向前/向后分页