Tương tác với API GraphQL
Tương tác với API GraphQLXử lý payload của mutation

Xử lý payload của mutation

Các trường mutation có thể được cấu hình để trả về một trong 2 kiểu thực thể khác nhau:

  • Một kiểu đối tượng payload
  • Trực tiếp thực thể đã được biến đổi

Kiểu đối tượng payload

Một kiểu đối tượng payload chứa tất cả dữ liệu liên quan đến mutation:

  • Trạng thái của mutation (thành công hay thất bại)
  • Các lỗi (nếu có) sử dụng các kiểu GraphQL riêng biệt, hoặc
  • Thực thể đã được biến đổi thành công

Ví dụ, mutation updatePost trả về một đối tượng kiểu PostUpdateMutationPayload, và chúng ta vẫn cần truy vấn trường post của nó để lấy thực thể bài viết đã được cập nhật:

mutation UpdatePost {
  updatePost(input: {
    id: 1724,
    title: "New title",
    status: publish
  }) {
    # This is the status of the mutation: SUCCESS or FAILURE
    status
    errors {
      __typename
      ...on ErrorPayload {
        message
      }
    }
    post {
      id
      title
      # This is the status of the post: publish, pending, trash, etc
      status
    }
  }
}

Đối tượng payload cho phép chúng ta biểu diễn các lỗi tốt hơn, thậm chí có một kiểu GraphQL duy nhất cho từng loại lỗi. Điều này cho phép chúng ta trình bày các phản ứng khác nhau cho các lỗi khác nhau trong ứng dụng, qua đó cải thiện trải nghiệm người dùng.

Trong ví dụ trên, nếu thao tác thành công, chúng ta sẽ nhận được:

{
  "data": {
    "updatePost": {
      "status": "SUCCESS",
      "errors": null,
      "post": {
        "id": 1724,
        "title": "Some title",
        "status": "publish"
      }
    }
  }
}

Nếu người dùng chưa đăng nhập, chúng ta sẽ nhận được:

{
  "data": {
    "updatePost": {
      "status": "FAILURE",
      "errors": [
        {
          "__typename": "UserIsNotLoggedInErrorPayload",
          "message": "You must be logged in to create or update custom posts"
        }
      ],
      "post": null
    }
  }
}

Nếu người dùng không có quyền chỉnh sửa bài viết, chúng ta sẽ nhận được:

{
  "data": {
    "updatePost": {
      "status": "FAILURE",
      "errors": [
        {
          "__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
          "message": "Your user doesn't have permission for editing custom posts."
        }
      ],
      "post": null
    }
  }
}

Ở chế độ này, schema GraphQL sẽ chứa nhiều kiểu bổ sung MutationPayload, MutationErrorPayloadUnionErrorPayload, do đó nó sẽ có kích thước lớn hơn:

Schema GraphQL với các kiểu đối tượng payload cho mutation

Truy vấn các đối tượng payload của mutation

Mỗi mutation trong schema có một trường tương ứng để truy vấn các đối tượng payload vừa được tạo, với tên {mutationName}MutationPayloadObjects.

Các trường này bao gồm:

  • addCommentToCustomPostMutationPayloadObjects (cho addCommentToCustomPost)
  • createCustomPostMutationPayloadObjects (cho createCustomPost)
  • createMediaItemMutationPayloadObjects (cho createMediaItem)
  • createPageMutationPayloadObjects (cho createPage)
  • createPostMutationPayloadObjects (cho createPost)
  • removeFeaturedImageFromCustomPostMutationPayloadObjects (cho removeFeaturedImageFromCustomPost)
  • replyCommentMutationPayloadObjects (cho replyComment)
  • setCategoriesOnPostMutationPayloadObjects (cho setCategoriesOnPost)
  • setFeaturedImageOnCustomPostMutationPayloadObjects (cho setFeaturedImageOnCustomPost)
  • setTagsOnPostMutationPayloadObjects (cho setTagsOnPost)
  • updateCustomPostMutationPayloadObjects (cho updateCustomPost)
  • updatePageMutationPayloadObjects (cho updatePage)
  • updatePostMutationPayloadObjects (cho updatePost)

Các trường này cho phép chúng ta lấy kết quả của các mutation được thực thi bằng @applyField trong khi duyệt qua các phần tử trong một mảng.

Ví dụ, truy vấn sau đây nhân bản bài viết theo loạt:

query GetPostsAndExportData
{
  postsToDuplicate: posts {
    title
    rawContent
    excerpt
 
    # Already create (and export) the inputs for the mutation
    postInput: _echo(value: {
      title: $__title
      contentAs: {
        html: $__rawContent
      },
      excerpt: $__excerpt
    })
      @export(as: "postInput", type: LIST)
      @remove
  }
}
 
mutation CreatePosts
  @depends(on: "GetPostsAndExportData")
{
  createdPostMutationPayloadObjectIDs: _echo(value: $postInput)
    @underEachArrayItem(
      passValueOnwardsAs: "input"
    )
      @applyField(
        name: "createPost"
        arguments: {
          input: $input
        },
        setResultInResponse: true
      )
    @export(as: "createdPostMutationPayloadObjectIDs")
}
 
query DuplicatePosts
  @depends(on: "CreatePosts")
{
  createdPostMutationObjectPayloads: createPostMutationPayloadObjects(input: {
    ids: $createdPostMutationPayloadObjectIDs
  }) {
    status
    errors {
      __typename
      ...on ErrorPayload {
        message
      }
    }
    post {
      id
      title
      rawContent
      excerpt
    }
  }
}

Theo mặc định, các trường này không được thêm vào schema GraphQL. Để làm điều đó, chúng ta phải chọn tùy chọn "Use payload types for mutations, and add fields to query those payload objects".

Thực thể đã biến đổi

Mutation sẽ trả về trực tiếp thực thể đã biến đổi trong trường hợp thành công, hoặc null trong trường hợp thất bại, và bất kỳ thông báo lỗi nào sẽ được hiển thị trong mục errors ở cấp cao nhất của phản hồi JSON.

Ví dụ, mutation updatePost sẽ trả về đối tượng kiểu Post:

mutation UpdatePost {
  updatePost(input: {
    id: 1724,
    title: "New title",
    status: publish
  }) {
    id
    title
    status
  }
}

Nếu thao tác thành công, chúng ta sẽ nhận được:

{
  "data": {
    "updatePost": {
      "id": 1724,
      "title": "Some title",
      "status": "publish"
    }
  }
}

Trong trường hợp có lỗi, chúng sẽ xuất hiện dưới mục errors của phản hồi. Ví dụ, nếu người dùng chưa đăng nhập, chúng ta sẽ nhận được:

{
    "errors": [
      {
        "message": "You must be logged in to create or update custom posts'",
        "locations": [
          {
            "line": 2,
            "column": 3
          }
        ]
      }
  ],
  "data": {
    "updatePost": null
  }
}

Chúng ta cần lưu ý rằng, kết quả là, mục errors ở cấp cao nhất sẽ chứa không chỉ các lỗi cú pháp, lỗi xác thực schema và lỗi logic (ví dụ: không truyền tên đối số của trường, yêu cầu trường không tồn tại, hoặc gọi _sendHTTPRequest khi mạng bị ngắt tương ứng), mà còn cả các lỗi "xác thực nội dung" (ví dụ: "bạn không được phép chỉnh sửa bài viết này").

Vì không có thêm kiểu nào được bổ sung, schema GraphQL sẽ trông gọn gàng hơn:

Schema GraphQL không có kiểu đối tượng payload cho mutation

Xử lý kiểu đối tượng payload cho mutation

Hãy xem cách xử lý tùy chọn đầu tiên, kiểu đối tượng payload.

Các mutation trong schema trả về một đối tượng payload, cung cấp bất kỳ lỗi nào phát sinh từ mutation, hoặc đối tượng đã được chỉnh sửa nếu thành công (2 thuộc tính này thường loại trừ lẫn nhau: hoặc errors hoặc object sẽ có giá trị, và cái còn lại sẽ là null).

Các lỗi được cung cấp thông qua một kiểu "ErrorPayloadUnion", chứa tất cả các lỗi có thể xảy ra cho mutation đó. Mỗi lỗi có thể xảy ra là một kiểu "ErrorPayload" triển khai interface ErrorPayload.

Ví dụ, thao tác updatePost trả về một PostUpdateMutationPayload, chứa các trường sau:

  • status: liệu thao tác có thành công hay không, với giá trị SUCCESS hoặc FAILURE
  • postpostID: đối tượng bài viết đã cập nhật và ID của nó, nếu việc cập nhật thành công
  • errors: danh sách CustomPostUpdateMutationErrorPayloadUnion, nếu việc cập nhật thất bại.

Kiểu union CustomPostUpdateMutationErrorPayloadUnion chứa danh sách tất cả các lỗi có thể xảy ra khi chỉnh sửa một custom post:

  • CustomPostDoesNotExistErrorPayload
  • GenericErrorPayload
  • LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload
  • LoggedInUserHasNoPermissionToEditCustomPostErrorPayload
  • LoggedInUserHasNoPublishingCustomPostCapabilityErrorPayload
  • UserIsNotLoggedInErrorPayload

Kiểu lỗi GenericErrorPayload được chứa trong tất cả các kiểu "ErrorPayloadUnion". Nó được sử dụng khi không thể xác định được lý do cụ thể của lỗi, chẳng hạn khi wp_update_post chỉ đơn giản tạo ra WP_Error. Kiểu này cung cấp hai trường bổ sung: codedata.

Sau đó, để thực thi mutation updatePost, chúng ta có thể thực thi:

mutation UpdatePost(
  $postId: ID!
  $title: String!
) {
  updatePost(
    input: {
      id: $postId,
      title: $title,
    }
  ) {
    status
    errors {
      __typename
      ...on ErrorPayload {
        message
      }
      ...on GenericErrorPayload {
        code
      }
    }
    post {
      id
      title
    }
  }
}

Nếu thao tác thành công, chúng ta sẽ nhận được:

{
  "data": {
    "updatePost": {
      "status": "SUCCESS",
      "errors": null,
      "post": {
        "id": 1724,
        "title": "This incredible title"
      }
    }
  }
}

Nếu người dùng chưa đăng nhập, chúng ta sẽ nhận được:

{
  "data": {
    "updatePost": {
      "status": "FAILURE",
      "errors": [
        {
          "__typename": "UserIsNotLoggedInErrorPayload",
          "message": "You must be logged in to create or update custom posts"
        }
      ],
      "post": null
    }
  }
}

Nếu người dùng không có quyền chỉnh sửa bài viết, chúng ta sẽ nhận được:

{
  "data": {
    "updatePost": {
      "status": "FAILURE",
      "errors": [
        {
          "__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
          "message": "Your user doesn't have permission for editing custom posts."
        }
      ],
      "post": null
    }
  }
}