GraphQL APIとのインタラクション
GraphQL APIとのインタラクションミューテーションペイロードの処理

ミューテーションペイロードの処理

ミューテーションフィールドは、次の2種類のエンティティ型のいずれかを返すように設定できます。

  • ペイロードオブジェクト型
  • ミューテーションされたエンティティを直接返す

ペイロードオブジェクト型

ペイロードオブジェクト型には、ミューテーションに関するすべてのデータが含まれます。

  • ミューテーションのステータス(成功または失敗)
  • エラー(存在する場合)は独自の GraphQL 型を使用して表現
  • ミューテーションが成功した場合のエンティティ

たとえば、ミューテーション updatePostPostUpdateMutationPayload 型のオブジェクトを返し、更新された投稿エンティティを取得するにはそのフィールド post をさらにクエリする必要があります。

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
    }
  }
}

ペイロードオブジェクトを使用することで、エラーをより適切に表現できます。エラーの種類ごとに固有の GraphQL 型を持つことも可能で、これによりアプリケーションでエラーの種類に応じた異なる対応を示すことができ、ユーザーエクスペリエンスが向上します。

上記の例で操作が成功した場合、次のレスポンスを受け取ります。

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

ユーザーがログインしていない場合、次のレスポンスを受け取ります。

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

ユーザーが投稿を編集する権限を持っていない場合、次のレスポンスを受け取ります。

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

このモードでは、GraphQL スキーマに MutationPayloadMutationErrorPayloadUnionErrorPayload といった追加の型が多数含まれるため、スキーマのサイズが大きくなります。

GraphQL schema with payload object types for mutations

ミューテーションペイロードオブジェクトのクエリ

スキーマ内のすべてのミューテーションには、直近に作成されたペイロードオブジェクトをクエリするための対応フィールドがあり、その名前は {mutationName}MutationPayloadObjects です。

これらのフィールドには次のものが含まれます。

  • addCommentToCustomPostMutationPayloadObjectsaddCommentToCustomPost 用)
  • createCustomPostMutationPayloadObjectscreateCustomPost 用)
  • createMediaItemMutationPayloadObjectscreateMediaItem 用)
  • createPageMutationPayloadObjectscreatePage 用)
  • createPostMutationPayloadObjectscreatePost 用)
  • removeFeaturedImageFromCustomPostMutationPayloadObjectsremoveFeaturedImageFromCustomPost 用)
  • replyCommentMutationPayloadObjectsreplyComment 用)
  • setCategoriesOnPostMutationPayloadObjectssetCategoriesOnPost 用)
  • setFeaturedImageOnCustomPostMutationPayloadObjectssetFeaturedImageOnCustomPost 用)
  • setTagsOnPostMutationPayloadObjectssetTagsOnPost 用)
  • updateCustomPostMutationPayloadObjectsupdateCustomPost 用)
  • updatePageMutationPayloadObjectsupdatePage 用)
  • updatePostMutationPayloadObjectsupdatePost 用)

これらのフィールドにより、配列内のアイテムを反復処理しながら @applyField を使用して実行されたミューテーションの結果を取得できます。

たとえば、次のクエリは投稿を一括で複製します。

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
    }
  }
}

デフォルトでは、これらのフィールドは GraphQL スキーマに追加されません。追加するには、「Use payload types for mutations, and add fields to query those payload objects」オプションを選択する必要があります。

ミューテーションされたエンティティ

ミューテーションは成功した場合にミューテーションされたエンティティを直接返し、失敗した場合は null を返します。エラーメッセージは JSON レスポンスのトップレベルの errors エントリに表示されます。

たとえば、ミューテーション updatePostPost 型のオブジェクトを返します。

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

操作が成功した場合、次のレスポンスを受け取ります。

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

エラーが発生した場合、それらはレスポンスの errors エントリに表示されます。たとえば、ユーザーがログインしていない場合は次のレスポンスを受け取ります。

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

注意すべき点として、この結果としてトップレベルの errors エントリには、構文エラー、スキーマ検証エラー、ロジックエラー(例:フィールド引数名の未指定、存在しないフィールドのリクエスト、ネットワークダウン時の _sendHTTPRequest 呼び出しなど)だけでなく、「コンテンツ検証」エラー(例:「この投稿を変更する権限がありません」)も含まれるようになります。

追加の型が存在しないため、GraphQL スキーマはよりスリムになります。

GraphQL schema without payload object types for mutations

ミューテーションのペイロードオブジェクト型の処理

最初のオプションであるペイロードオブジェクト型の処理方法を見ていきましょう。

スキーマ内のミューテーションは何らかのペイロードオブジェクトを返し、ミューテーションによって発生したエラーか、成功した場合は変更済みオブジェクトを提供します(これら2つのプロパティはほぼ排他的です。errors または object のどちらかに値が入り、もう一方は null になります)。

エラーは、そのミューテーションで考えられるすべてのエラーを含む「ErrorPayloadUnion」型を通じて提供されます。考えられる各エラーは、インターフェース ErrorPayload を実装する何らかの「ErrorPayload」型です。

たとえば、操作 updatePostPostUpdateMutationPayload を返し、次のフィールドが含まれます。

  • status: 操作が成功したかどうかを示し、SUCCESS または FAILURE の値を持ちます
  • post および postID: 更新が成功した場合の更新済み投稿オブジェクトとその ID
  • errors: 更新が失敗した場合の CustomPostUpdateMutationErrorPayloadUnion のリスト

ユニオン型 CustomPostUpdateMutationErrorPayloadUnion には、カスタム投稿を変更する際に発生し得るすべてのエラーのリストが含まれます。

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

エラー型 GenericErrorPayload はすべての「ErrorPayloadUnion」型に含まれます。wp_update_post が単純に WP_Error を生成する場合など、エラーの具体的な原因を特定できない場合に使用されます。この型は追加フィールドとして codedata を提供します。

updatePost ミューテーションを実行するには、次のように実行します。

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

操作が成功した場合、次のレスポンスを受け取ります。

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

ユーザーがログインしていない場合、次のレスポンスを受け取ります。

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

ユーザーが投稿を編集する権限を持っていない場合、次のレスポンスを受け取ります。

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