7.6 KiB
7.6 KiB
变异模式
本参考文档涵盖了编写高效 GraphQL 变异的模式。
目录
变异结构
基础变异
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
createdAt
}
}
变量:
{
"input": {
"title": "My Post",
"content": "Post content..."
}
}
带多个参数的变异
mutation UpdatePost($id: ID!, $input: UpdatePostInput!) {
updatePost(id: $id, input: $input) {
id
title
updatedAt
}
}
多个变异
在单个请求中执行多个变异(顺序执行):
mutation SetupUserProfile($userId: ID!, $profileInput: ProfileInput!, $settingsInput: SettingsInput!) {
updateProfile(userId: $userId, input: $profileInput) {
id
bio
}
updateSettings(userId: $userId, input: $settingsInput) {
id
theme
notifications
}
}
输入模式
单一输入对象
推荐模式——单一输入参数:
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
email
}
}
{
"input": {
"email": "user@example.com",
"name": "John Doe",
"password": "secret123"
}
}
嵌套输入对象
mutation CreateOrder($input: CreateOrderInput!) {
createOrder(input: $input) {
id
total
}
}
{
"input": {
"items": [
{ "productId": "prod_1", "quantity": 2 },
{ "productId": "prod_2", "quantity": 1 }
],
"shippingAddress": {
"street": "123 Main St",
"city": "New York",
"country": "US"
}
}
}
可选字段
mutation UpdateUser($id: ID!, $input: UpdateUserInput!) {
updateUser(id: $id, input: $input) {
id
name
bio
}
}
{
"id": "user_123",
"input": {
"name": "New Name"
// bio 未包含——不会被更改
}
}
响应选择
返回修改后的对象
始终返回带有更新字段的变异对象:
mutation UpdatePost($id: ID!, $input: UpdatePostInput!) {
updatePost(id: $id, input: $input) {
id
title
content
updatedAt # 服务端设置的字段
}
}
返回相关对象
如果变异影响了关联数据,请包含它:
mutation AddComment($input: AddCommentInput!) {
addComment(input: $input) {
id
body
post {
id
commentCount # 更新后的计数
}
author {
id
name
}
}
}
为缓存更新返回
选择更新缓存所需的字段:
mutation DeletePost($id: ID!) {
deletePost(id: $id) {
id # 需要从缓存中移除
author {
id
postCount # 可能需要递减
}
}
}
为列表更新返回连接
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
createdAt
author {
id
posts(first: 1) {
edges {
node {
id
}
}
totalCount
}
}
}
}
错误处理
查询结果联合类型
当 schema 使用联合类型来表示错误时:
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
... on CreateUserSuccess {
user {
id
email
}
}
... on ValidationError {
message
field
}
... on EmailAlreadyExists {
message
existingUserId
}
}
}
处理所有情况
const result = await client.mutate({
mutation: CREATE_USER,
variables: { input },
});
const { createUser } = result.data;
switch (createUser.__typename) {
case "CreateUserSuccess":
// 处理成功
return createUser.user;
case "ValidationError":
// 处理验证错误
throw new ValidationError(createUser.field, createUser.message);
case "EmailAlreadyExists":
// 处理特定的业务错误
throw new EmailExistsError(createUser.existingUserId);
}
GraphQL 错误
处理网络错误和 GraphQL 错误:
try {
const result = await client.mutate({
mutation: CREATE_POST,
variables: { input },
});
return result.data.createPost;
} catch (error) {
if (error.graphQLErrors?.length) {
// 处理 GraphQL 错误
const gqlError = error.graphQLErrors[0];
if (gqlError.extensions?.code === "UNAUTHENTICATED") {
// 重定向到登录页
}
}
if (error.networkError) {
// 处理网络错误
}
throw error;
}
乐观更新
为乐观响应选择字段
包含所有将立即显示的字段:
mutation LikePost($postId: ID!) {
likePost(postId: $postId) {
id
likeCount
isLikedByViewer
}
}
client.mutate({
mutation: LIKE_POST,
variables: { postId: "post_123" },
optimisticResponse: {
likePost: {
__typename: "Post",
id: "post_123",
likeCount: currentCount + 1,
isLikedByViewer: true,
},
},
});
包含创建的 ID
对于创建型变异,使用临时 ID:
mutation AddComment($input: AddCommentInput!) {
addComment(input: $input) {
id
body
createdAt
author {
id
name
avatarUrl
}
}
}
client.mutate({
mutation: ADD_COMMENT,
variables: { input: { postId, body } },
optimisticResponse: {
addComment: {
__typename: "Comment",
id: `temp-${Date.now()}`, // 临时 ID
body,
createdAt: new Date().toISOString(),
author: {
__typename: "User",
id: currentUser.id,
name: currentUser.name,
avatarUrl: currentUser.avatarUrl,
},
},
},
});
变异命名
命名约定
| 操作 | 模式 | 示例 |
|---|---|---|
| 创建(Create) | Create{Type} |
CreateUser, CreatePost |
| 更新(Update) | Update{Type} |
UpdateUser, UpdatePost |
| 删除(Delete) | Delete{Type} |
DeleteUser, DeletePost |
| 操作(Action) | {Verb}{Type} |
PublishPost, ArchiveProject |
| 关系(Relationship) | {Add/Remove}{Type} |
AddTeamMember, RemoveTag |
好的命名示例
mutation CreateUser($input: CreateUserInput!) { ... }
mutation UpdateUserProfile($userId: ID!, $input: ProfileInput!) { ... }
mutation DeletePost($id: ID!) { ... }
mutation PublishArticle($id: ID!) { ... }
mutation ArchiveProject($id: ID!) { ... }
mutation AddItemToCart($input: AddItemInput!) { ... }
mutation RemoveTeamMember($teamId: ID!, $userId: ID!) { ... }
mutation FollowUser($userId: ID!) { ... }
mutation MarkNotificationAsRead($id: ID!) { ... }
操作名称与服务端一致
使客户端操作名称与服务端变异名称一致:
# 服务端 schema
type Mutation {
createPost(input: CreatePostInput!): Post!
}
# 客户端操作——名称反映其行为
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
}
}
上下文特定的名称
当同一个变异用于不同场景时,添加上下文:
# 用于创建草稿
mutation CreateDraftPost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
status
}
}
# 用于创建并立即发布
mutation CreateAndPublishPost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
status
publishedAt
}
}