GraphQL Schema 定义 #
Schema 是什么? #
Schema 是 GraphQL API 的蓝图,它定义了 API 的类型系统、操作入口和数据结构。
text
┌─────────────────────────────────────────────────────────────┐
│ Schema 的作用 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ Schema │ ← API 契约 │
│ └──────┬──────┘ │
│ │ │
│ ┌────┼────┬────────┐ │
│ ▼ ▼ ▼ ▼ │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │类型│ │查询│ │变更│ │订阅│ │
│ │定义│ │入口│ │入口│ │入口│ │
│ └────┘ └────┘ └────┘ └────┘ │
│ │
│ 作用: │
│ ✅ 定义数据模型 │
│ ✅ 定义操作入口 │
│ ✅ 生成文档 │
│ ✅ 验证查询 │
│ ✅ 类型检查 │
│ │
└─────────────────────────────────────────────────────────────┘
基本结构 #
根类型 #
GraphQL Schema 有三个根类型:
graphql
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
Query 类型 #
定义所有查询操作:
graphql
type Query {
users: [User!]!
user(id: ID!): User
posts(limit: Int, offset: Int): [Post!]!
post(id: ID!): Post
search(query: String!): [SearchResult!]!
}
Mutation 类型 #
定义所有变更操作:
graphql
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): DeleteResult!
createPost(input: CreatePostInput!): Post!
updatePost(id: ID!, input: UpdatePostInput!): Post!
deletePost(id: ID!): DeleteResult!
}
Subscription 类型 #
定义所有订阅操作:
graphql
type Subscription {
onUserCreated: User!
onUserUpdated(id: ID!): User!
onPostCreated: Post!
onCommentAdded(postId: ID!): Comment!
}
类型定义 #
对象类型 #
graphql
type User {
id: ID!
name: String!
email: String!
age: Int
status: UserStatus!
role: Role!
posts: [Post!]!
comments: [Comment!]!
createdAt: DateTime!
updatedAt: DateTime
}
字段说明 #
graphql
type Post {
id: ID!
title: String!
content: String!
excerpt: String
status: PostStatus!
author: User!
comments(first: Int, after: String): CommentConnection!
tags: [String!]!
viewCount: Int!
createdAt: DateTime!
publishedAt: DateTime
}
字段参数 #
graphql
type Query {
user(id: ID!): User
users(
filter: UserFilter
orderBy: UserOrderBy
first: Int
after: String
): UserConnection!
search(
query: String!
type: SearchType
limit: Int = 10
): [SearchResult!]!
}
输入类型 #
输入类型用于传递复杂参数:
graphql
input CreateUserInput {
name: String!
email: String!
password: String!
age: Int
role: Role = USER
}
input UpdateUserInput {
name: String
email: String
age: Int
status: UserStatus
}
input UserFilter {
status: UserStatus
role: Role
age: IntRange
name: StringFilter
}
input IntRange {
gte: Int
lte: Int
}
input StringFilter {
eq: String
contains: String
startsWith: String
endsWith: String
}
枚举类型 #
graphql
enum UserStatus {
ACTIVE
INACTIVE
PENDING
SUSPENDED
DELETED
}
enum Role {
ADMIN
MODERATOR
USER
GUEST
}
enum PostStatus {
DRAFT
PUBLISHED
ARCHIVED
DELETED
}
enum SortOrder {
ASC
DESC
}
接口类型 #
接口定义一组公共字段:
graphql
interface Node {
id: ID!
createdAt: DateTime!
}
interface Content {
id: ID!
title: String!
author: User!
createdAt: DateTime!
}
type Post implements Node & Content {
id: ID!
title: String!
content: String!
author: User!
createdAt: DateTime!
tags: [String!]!
}
type Page implements Node & Content {
id: ID!
title: String!
body: String!
author: User!
createdAt: DateTime!
slug: String!
}
查询接口:
graphql
type Query {
node(id: ID!): Node
content(id: ID!): Content
}
使用内联片段:
graphql
query {
content(id: "1") {
id
title
author {
name
}
... on Post {
tags
}
... on Page {
slug
}
}
}
联合类型 #
联合类型表示多种类型之一:
graphql
union SearchResult = User | Post | Comment
union Media = Image | Video | Audio
union Notification = UserNotification | SystemNotification | MessageNotification
查询联合类型:
graphql
query {
search(query: "GraphQL") {
... on User {
id
name
email
}
... on Post {
id
title
excerpt
}
... on Comment {
id
content
}
}
}
连接类型 #
用于分页的标准类型:
graphql
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
使用:
graphql
type Query {
users(
first: Int
after: String
last: Int
before: String
filter: UserFilter
orderBy: UserOrderBy
): UserConnection!
}
负载类型 #
变更操作的返回类型:
graphql
type UserMutationPayload {
user: User
success: Boolean!
message: String
errors: [FieldError!]
}
type FieldError {
field: String!
message: String!
code: String
}
type DeleteResult {
success: Boolean!
message: String
deletedId: ID
}
使用:
graphql
type Mutation {
createUser(input: CreateUserInput!): UserMutationPayload!
updateUser(id: ID!, input: UpdateUserInput!): UserMutationPayload!
deleteUser(id: ID!): DeleteResult!
}
指令定义 #
自定义指令:
graphql
directive @auth(requires: Role = USER) on FIELD_DEFINITION
directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE
directive @validate(constraint: String!) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
directive @cache(ttl: Int!) on FIELD_DEFINITION
directive @rateLimit(limit: Int!, duration: Int!) on FIELD_DEFINITION
使用指令:
graphql
type Query {
users: [User!]! @auth(requires: ADMIN)
user(id: ID!): User @cache(ttl: 300)
}
type Mutation {
createUser(input: CreateUserInput!): User! @rateLimit(limit: 10, duration: 60)
}
type User {
id: ID!
name: String!
email: String! @deprecated(reason: "Use `emails` field instead")
emails: [Email!]!
}
模块化 Schema #
大型项目需要模块化组织:
文件结构 #
text
schema/
├── index.graphql
├── types/
│ ├── user.graphql
│ ├── post.graphql
│ ├── comment.graphql
│ └── common.graphql
├── inputs/
│ ├── user.inputs.graphql
│ ├── post.inputs.graphql
│ └── filter.inputs.graphql
├── enums/
│ ├── status.graphql
│ └── role.graphql
└── directives/
└── auth.graphql
用户模块 #
graphql
type User implements Node {
id: ID!
name: String!
email: String!
avatar: String
status: UserStatus!
role: Role!
posts(first: Int, after: String): PostConnection!
comments(first: Int, after: String): CommentConnection!
createdAt: DateTime!
updatedAt: DateTime
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
extend type Query {
user(id: ID!): User
users(
first: Int
after: String
filter: UserFilter
orderBy: UserOrderBy
): UserConnection!
me: User
}
extend type Mutation {
createUser(input: CreateUserInput!): UserMutationPayload!
updateUser(id: ID!, input: UpdateUserInput!): UserMutationPayload!
deleteUser(id: ID!): DeleteResult!
}
extend type Subscription {
onUserCreated: User!
onUserUpdated(id: ID!): User!
}
公共类型 #
graphql
interface Node {
id: ID!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
scalar DateTime
scalar JSON
scalar Upload
type DeleteResult {
success: Boolean!
message: String
deletedId: ID
}
type FieldError {
field: String!
message: String!
code: String
}
合并 Schema #
javascript
const { mergeTypeDefs } = require('@graphql-tools/merge');
const userSchema = require('./types/user.graphql');
const postSchema = require('./types/post.graphql');
const commonSchema = require('./types/common.graphql');
const typeDefs = mergeTypeDefs([
userSchema,
postSchema,
commonSchema
]);
Schema 设计最佳实践 #
1. 命名规范 #
graphql
type User {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
profilePicture: String
createdAt: DateTime!
updatedAt: DateTime
}
type Query {
user(id: ID!): User
users(first: Int, after: String): UserConnection!
userByEmail(email: String!): User
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): DeleteResult!
}
2. 非空设计 #
graphql
type User {
id: ID!
name: String!
email: String!
bio: String
avatar: String
phone: String
}
3. 分页设计 #
graphql
type Query {
users(first: Int, after: String): UserConnection!
posts(first: Int, after: String): PostConnection!
comments(first: Int, after: String): CommentConnection!
}
4. 过滤和排序 #
graphql
input UserFilter {
status: UserStatus
role: Role
search: String
createdAt: DateRange
}
input UserOrderBy {
field: UserOrderField!
direction: SortOrder!
}
enum UserOrderField {
NAME
EMAIL
CREATED_AT
UPDATED_AT
}
type Query {
users(
filter: UserFilter
orderBy: UserOrderBy
first: Int
after: String
): UserConnection!
}
5. 错误处理 #
graphql
type UserMutationPayload {
user: User
success: Boolean!
message: String
errors: [FieldError!]
}
type FieldError {
field: String!
message: String!
code: ErrorCode!
}
enum ErrorCode {
VALIDATION_ERROR
NOT_FOUND
UNAUTHORIZED
FORBIDDEN
CONFLICT
INTERNAL_ERROR
}
完整示例 #
graphql
scalar DateTime
scalar JSON
scalar Upload
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
enum UserStatus {
ACTIVE
INACTIVE
PENDING
SUSPENDED
}
enum Role {
ADMIN
MODERATOR
USER
}
enum PostStatus {
DRAFT
PUBLISHED
ARCHIVED
}
enum SortOrder {
ASC
DESC
}
interface Node {
id: ID!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type User implements Node {
id: ID!
name: String!
email: String!
avatar: String
status: UserStatus!
role: Role!
posts(first: Int, after: String, status: PostStatus): PostConnection!
comments(first: Int, after: String): CommentConnection!
createdAt: DateTime!
updatedAt: DateTime
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type Post implements Node {
id: ID!
title: String!
content: String!
excerpt: String
status: PostStatus!
author: User!
comments(first: Int, after: String): CommentConnection!
tags: [String!]!
viewCount: Int!
createdAt: DateTime!
publishedAt: DateTime
updatedAt: DateTime
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type PostEdge {
node: Post!
cursor: String!
}
type Comment implements Node {
id: ID!
content: String!
author: User!
post: Post!
parent: Comment
replies(first: Int, after: String): CommentConnection!
createdAt: DateTime!
updatedAt: DateTime
}
type CommentConnection {
edges: [CommentEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type CommentEdge {
node: Comment!
cursor: String!
}
input CreateUserInput {
name: String!
email: String!
password: String!
role: Role = USER
}
input UpdateUserInput {
name: String
email: String
avatar: String
status: UserStatus
}
input UserFilter {
status: UserStatus
role: Role
search: String
}
input UserOrderBy {
field: UserOrderField!
direction: SortOrder!
}
enum UserOrderField {
NAME
EMAIL
CREATED_AT
}
input CreatePostInput {
title: String!
content: String!
excerpt: String
status: PostStatus = DRAFT
tags: [String!]
}
input UpdatePostInput {
title: String
content: String
excerpt: String
status: PostStatus
tags: [String!]
}
input PostFilter {
status: PostStatus
authorId: ID
search: String
}
input PostOrderBy {
field: PostOrderField!
direction: SortOrder!
}
enum PostOrderField {
TITLE
CREATED_AT
PUBLISHED_AT
VIEW_COUNT
}
type UserMutationPayload {
user: User
success: Boolean!
message: String
errors: [FieldError!]
}
type PostMutationPayload {
post: Post
success: Boolean!
message: String
errors: [FieldError!]
}
type FieldError {
field: String!
message: String!
code: String
}
type DeleteResult {
success: Boolean!
message: String
deletedId: ID
}
type Query {
me: User
user(id: ID!): User
users(
filter: UserFilter
orderBy: UserOrderBy
first: Int
after: String
): UserConnection!
post(id: ID!): Post
posts(
filter: PostFilter
orderBy: PostOrderBy
first: Int
after: String
): PostConnection!
comment(id: ID!): Comment
search(query: String!, type: SearchType, limit: Int = 10): [SearchResult!]!
node(id: ID!): Node
}
enum SearchType {
USER
POST
COMMENT
ALL
}
union SearchResult = User | Post | Comment
type Mutation {
createUser(input: CreateUserInput!): UserMutationPayload!
updateUser(id: ID!, input: UpdateUserInput!): UserMutationPayload!
deleteUser(id: ID!): DeleteResult!
createPost(input: CreatePostInput!): PostMutationPayload!
updatePost(id: ID!, input: UpdatePostInput!): PostMutationPayload!
deletePost(id: ID!): DeleteResult!
createComment(input: CreateCommentInput!): Comment!
updateComment(id: ID!, input: UpdateCommentInput!): Comment!
deleteComment(id: ID!): DeleteResult!
}
input CreateCommentInput {
content: String!
postId: ID!
parentId: ID
}
input UpdateCommentInput {
content: String!
}
type Subscription {
onUserCreated: User!
onUserUpdated(id: ID!): User!
onPostCreated: Post!
onPostUpdated(id: ID!): Post!
onCommentAdded(postId: ID!): Comment!
}
directive @auth(requires: Role = USER) on FIELD_DEFINITION
directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE
下一步 #
现在你已经掌握了 GraphQL Schema 的设计方法,接下来学习 类型系统,深入了解 GraphQL 的类型机制!
最后更新:2026-03-29