スキーマチュートリアル
スキーマチュートリアルレッスン19:外部APIからデータを取得する

レッスン19:外部APIからデータを取得する

HTTP Client 拡張機能を使用すると、ウェブサーバーに対してHTTPリクエストを実行できます。

このチュートリアルレッスンでは、以下の方法で外部APIからデータを取得する方法を説明します。

  • MailchimpのREST APIからメールリストのメンバーを取得し、そのメールアドレスを抽出してデータを活用する
  • GitHubのGraphQL APIからリポジトリを取得する

HTTPリクエストを実行する

MailchimpのAPIドキュメントによると、メールリストのメンバーデータを取得するには、REST APIに対して GET リクエストを送信する必要があります。

curl --request GET \
  --url 'https://us7.api.mailchimp.com/3.0/lists/{LIST_ID}/members' \
  --user 'username:password'

これをGato GraphQLで再現してみましょう。

グローバルフィールド _sendHTTPRequestHTTP Client 拡張機能が提供)を使用してHTTPリクエストを実行します。

query {
  _sendHTTPRequest(input: {
    url: "https://us7.api.mailchimp.com/3.0/lists/{LIST_ID}/members",
    method: GET,
    options: {
      auth: {
        username: "{USER}",
        password: "{API_TOKEN}"
      }
    }
  }) {
    body
    contentType
    statusCode
    headers
    serverHeader: header(name: "Server")
  }
}

フィールド _sendHTTPRequestHTTPResponse 型のオブジェクトを返します。クエリを実行すると、body フィールド(String 型)にレスポンスの生のコンテンツが含まれていることが確認できます。

{
  "data": {
    "_sendHTTPRequest": {
      "body": "{\"members\":[{\"id\":\"mSjGOg5qSb3dKTxPU9lhRZCxHGug8Mrt\",\"email_address\":\"vinesh@yahoo.com\",\"unique_email_id\":\"KObAXbEO3X\",\"contact_id\":\"JiCdz5EY67m3PKugW3bRE9VI1WjiBbjq\",\"full_name\":\"Vinesh Munak\",\"web_id\":443344389,\"email_type\":\"html\",\"status\":\"subscribed\",\"consents_to_one_to_one_messaging\":true,\"merge_fields\":{\"FNAME\":\"Vinesh\",\"LNAME\":\"Munak\",\"ADDRESS\":{\"addr1\":\"\",\"addr2\":\"\",\"city\":\"\",\"state\":\"\",\"zip\":\"\",\"country\":\"IN\"},\"PHONE\":\"\",\"BIRTHDAY\":\"\"},\"stats\":{\"avg_open_rate\":0.8,\"avg_click_rate\":0.6},\"ip_signup\":\"\",\"timestamp_signup\":\"\",\"ip_opt\":\"218.115.112.129\",\"timestamp_opt\":\"2020-12-31T06:55:17+00:00\",\"member_rating\":4,\"last_changed\":\"2020-12-31T06:55:17+00:00\",\"language\":\"\",\"vip\":false,\"email_client\":\"\",\"location\":{\"latitude\":2.18,\"longitude\":99.47,\"gmtoff\":8,\"dstoff\":8,\"country_code\":\"MY\",\"timezone\":\"asia/kuala_lumpur\",\"region\":\"10\"},\"source\":\"Admin Add\",\"tags_count\":0,\"tags\":[],\"list_id\":\"9nrwpfj0ou\",\"_links\":[{...}]},{...}],\"total_items\":4927,\"_links\":[{...}]}",
      "contentType": "application/json; charset=utf-8",
      "statusCode": 200,
      "headers": {
        "Server": "openresty",
        "Content-Type": "application/json; charset=utf-8",
        "Vary": "Accept-Encoding",
        "X-Request-Id": "177551d0-82e9-3d61-a664-177f61b91f80",
        "Link": "<https://us7.api.mailchimp.com/schema/3.0/Lists/Members/Collection.json>; rel=\"describedBy\"",
        "Date": "Thu, 13 Jul 2023 04:57:42 GMT",
        "Transfer-Encoding": "chunked",
        "Connection": "keep-alive,Transfer-Encoding"
      },
      "serverHeader": "openresty"
    }
  }
}

レスポンスのcontent-typeが application/json であるため、フィールド _strDecodeJSONObjectPHP Functions Via Schema 拡張機能)を使用して、ボディの生のコンテンツを String から JSONObject に変換できます。

query {
  _sendHTTPRequest(input: {
    url: "https://us7.api.mailchimp.com/3.0/lists/{LIST_ID}/members",
    method: GET,
    options: {
      auth: {
        username: "{USER}",
        password: "{API_TOKEN}"
      }
    }
  }) {
    body @remove
    bodyJSONObject: _strDecodeJSONObject(string: $__body)
  }
}

これでボディをJSONオブジェクトとしてアクセスできるようになります。

{
  "data": {
    "_sendHTTPRequest": {
      "bodyJSONObject": {
        "members": [
          {
            "id": "mSjGOg5qSb3dKTxPU9lhRZCxHGug8Mrt",
            "email_address": "vinesh@yahoo.com",
            "unique_email_id": "KObAXbEO3X",
            "contact_id": "JiCdz5EY67m3PKugW3bRE9VI1WjiBbjq",
            "full_name": "Vinesh Munak",
            "web_id": 443344389,
            "email_type": "html",
            "status": "subscribed",
            "consents_to_one_to_one_messaging": true,
            "merge_fields": {
              "FNAME": "Vinesh",
              "LNAME": "Munak",
              "ADDRESS": {
                "addr1": "",
                "addr2": "",
                "city": "",
                "state": "",
                "zip": "",
                "country": "IN"
              },
              "PHONE": "",
              "BIRTHDAY": ""
            },
            "stats": {
              "avg_open_rate": 0.8,
              "avg_click_rate": 0.6
            },
            "ip_signup": "",
            "timestamp_signup": "",
            "ip_opt": "218.115.112.129",
            "timestamp_opt": "2020-12-31T06:55:17+00:00",
            "member_rating": 4,
            "last_changed": "2020-12-31T06:55:17+00:00",
            "language": "",
            "vip": false,
            "email_client": "",
            "location": {
              "latitude": 2.18,
              "longitude": 99.47,
              "gmtoff": 8,
              "dstoff": 8,
              "country_code": "MY",
              "timezone": "asia/kuala_lumpur",
              "region": "10"
            },
            "source": "Admin Add",
            "tags_count": 0,
            "tags": [],
            "list_id": "9nrwpfj0ou",
            "_links": [
              {
                // ...
              },
              // ...
            ]
          },
          {
            // ...
          }
        ],
        "list_id": "9nrwpfj0ou",
        "total_items": 4927,
        "_links": [
          {
            // ...
          },
          // ...
        ]
      }
    }
  }
}

REST APIに接続する

HTTP Client は、content-type application/json のレスポンスをすでに処理するファンクションフィールドも提供しており、REST APIへの接続に適しています。

  • _sendJSONObjectItemHTTPRequest: コンテンツが単一のJSONオブジェクトの場合
  • _sendJSONObjectCollectionHTTPRequest: コンテンツがJSONオブジェクトのコレクションの場合

これらのフィールドはすでにレスポンスを JSONObject または [JSONObject] に変換します。

これらのフィールドは、レスポンスのステータスコードが成功(つまり 200201202 などの 200-299 の範囲)であることを期待します。これにより、レスポンスのボディをJSONとしてデコードした JSONObject をすでに返せるようになります。

そうでない場合、GraphQLレスポンスには対応するエラーが含まれます。

例えば、WP REST APIのエンドポイント /wp-json/wp/v2/posts/{postId}/ から存在しない投稿を取得しようとすると、レスポンスは次のようになります。

{
  "errors": [
    {
      "message": "Client error: `GET https://newapi.getpop.org/wp-json/wp/v2/posts/88888/` resulted in a `404 Not Found` response:\n{\"code\":\"rest_post_invalid_id\",\"message\":\"Invalid post ID.\",\"data\":{\"status\":404}}\n",
      "locations": [
        {
          "line": 3,
          "column": 17
        }
      ],
      "extensions": {
        "path": [
          "externalData: _sendJSONObjectItemHTTPRequest(input: {url: \"https://newapi.getpop.org/wp-json/wp/v2/posts/88888/\"}) @export(as: \"externalData\")",
          "query ConnectToAPI { ... }"
        ],
        "type": "QueryRoot",
        "field": "externalData: _sendJSONObjectItemHTTPRequest(input: {url: \"https://newapi.getpop.org/wp-json/wp/v2/posts/88888/\"}) @export(as: \"externalData\")",
        "id": "root",
        "code": "PoP/ComponentModel@e1"
      }
    }
  ],
  "data": {
    "externalData": null
  }
}

200s 以外のステータスコード(302404500 など)をエラーとして扱いたくない場合は、_sendHTTPRequest フィールドを使用する必要があります。

前のクエリを修正すると次のようになります。

query {
  _sendJSONObjectItemHTTPRequest(input: {
    url: "https://us7.api.mailchimp.com/3.0/lists/{LIST_ID}/members",
    method: GET,
    options: {
      auth: {
        username: "{USER}",
        password: "{API_TOKEN}"
      }
    }
  })
}

...次のレスポンスが得られます。

{
  "data": {
    "_sendJSONObjectItemHTTPRequest": {
      "members": [
        {
          "id": "mSjGOg5qSb3dKTxPU9lhRZCxHGug8Mrt",
          "email_address": "vinesh@yahoo.com",
          "unique_email_id": "KObAXbEO3X",
          "contact_id": "JiCdz5EY67m3PKugW3bRE9VI1WjiBbjq",
          "full_name": "Vinesh Munak",
          "web_id": 443344389,
          "email_type": "html",
          "status": "subscribed",
          "consents_to_one_to_one_messaging": true,
          "merge_fields": {
            "FNAME": "Vinesh",
            "LNAME": "Munak",
            "ADDRESS": {
              "addr1": "",
              "addr2": "",
              "city": "",
              "state": "",
              "zip": "",
              "country": "IN"
            },
            "PHONE": "",
            "BIRTHDAY": ""
          },
          "stats": {
            "avg_open_rate": 0.8,
            "avg_click_rate": 0.6
          },
          "ip_signup": "",
          "timestamp_signup": "",
          "ip_opt": "218.115.112.129",
          "timestamp_opt": "2020-12-31T06:55:17+00:00",
          "member_rating": 4,
          "last_changed": "2020-12-31T06:55:17+00:00",
          "language": "",
          "vip": false,
          "email_client": "",
          "location": {
            "latitude": 2.18,
            "longitude": 99.47,
            "gmtoff": 8,
            "dstoff": 8,
            "country_code": "MY",
            "timezone": "asia/kuala_lumpur",
            "region": "10"
          },
          "source": "Admin Add",
          "tags_count": 0,
          "tags": [],
          "list_id": "9nrwpfj0ou",
          "_links": [
            {
              // ...
            },
            // ...
          ]
        },
        {
          // ...
        }
      ],
      "list_id": "9nrwpfj0ou",
      "total_items": 4927,
      "_links": [
        {
          // ...
        },
        // ...
      ]
    }
  }
}

外部サーバーからであれ、同じサイトからであれ、WP REST APIへの接続は同じ手順で行います。

例えば、このGraphQLクエリは ?context=edit モードでローカルサイトからWP REST APIに接続します(そのため、アプリケーションパスワードの認証情報を提供する必要があります)。

query GetPostEditingDataFromRESTAPI(
  $postId: ID!,
  $username: String!,
  $applicationPassword: String!
) {
  siteURL: optionValue(name: "siteurl")
    @remove
 
  endpoint: _sprintf(
    string: "%s/wp-json/wp/v2/posts/%d/?context=edit",
    values: [
      $__siteURL,
      $postId,
    ]
  )
    @remove
 
  _sendJSONObjectItemHTTPRequest(input: {
    url: $__endpoint,
    method: GET,
    options: {
      auth: {
        username: $username,
        password: $applicationPassword
      }
    }
  })
}

以下の変数を渡すと:

{
  "postId": 1,
  "username": "{username}",
  "applicationPassword": "{application password}"
}

...レスポンスは次のようになります。

{
  "data": {
    "_sendJSONObjectItemHTTPRequest": {
      "id": 1,
      "date": "2020-04-17T13:06:58",
      "date_gmt": "2020-04-17T13:06:58",
      "guid": {
        "rendered": "https://mysite.com/?p=1",
        "raw": "https://mysite.com/?p=1"
      },
      "modified": "2020-04-17T13:06:58",
      "modified_gmt": "2020-04-17T13:06:58",
      "password": "",
      "slug": "hello-world",
      "status": "publish",
      "type": "post",
      "link": "https://mysite.com/hello-world/",
      "title": {
        "raw": "Hello world!",
        "rendered": "Hello world!"
      },
      "content": {
        "raw": "<!-- wp:paragraph -->\n<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>\n<!-- /wp:paragraph -->",
        "rendered": "\n<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>\n",
        "protected": false,
        "block_version": 1
      },
      "excerpt": {
        "raw": "",
        "rendered": "<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>\n",
        "protected": false
      },
      "author": 2,
      "featured_media": 0,
      "comment_status": "open",
      "ping_status": "open",
      "sticky": false,
      "template": "",
      "format": "standard",
      "meta": [],
      "categories": [
        1
      ],
      "tags": [],
      "permalink_template": "https://mysite.com/%postname%/",
      "generated_slug": "hello-world",
      "_links": {
        // ...
      }
    }
  }
}

GraphQL APIに接続する

HTTP Client は、GraphQL APIに便利に接続するためのファンクションフィールドも提供しています。

フィールド _sendGraphQLHTTPRequest は、GraphQLが期待する入力(クエリ、変数、オペレーション名)を受け取り、提供されたエンドポイントに対してGraphQLクエリを実行し、レスポンスを JSONObject に変換します。

このクエリは GitHubのGraphQL API に接続し、指定されたオーナーのリポジトリ一覧を取得します。

query FetchGitHubRepositories(
  $authorizationToken: String!
  $login: String!
  $numberRepos: Int! = 3
) {
  _sendGraphQLHTTPRequest(input:{
    endpoint: "https://api.github.com/graphql",
    query: """
    
query GetRepositoriesByOwner($login: String!, $numberRepos: Int!) {
  repositoryOwner(login: $login) {
    repositories(first: $numberRepos) {
      nodes {
        id
        name
        description
      }
    }
  }
}
 
    """,
    variables: [
      {
        name: "login",
        value: $login
      },
      {
        name: "numberRepos",
        value: $numberRepos
      }
    ],
    options: {
      auth: {
        password: $authorizationToken
      }
    }
  })
}

以下の variables を渡すと:

{
  "authorizationToken": "{ GITHUB ACCESS TOKEN }",
  "login": "leoloso"
}

...次のレスポンスが得られます。

{
  "data": {
    "_sendGraphQLHTTPRequest": {
      "data": {
        "repositoryOwner": {
          "repositories": {
            "nodes": [
              {
                "id": "MDEwOlJlcG9zaXRvcnk2NjcyMTIyNw==",
                "name": "PoP",
                "description": "Monorepo of the PoP project, including: a server-side component model in PHP, a GraphQL server, a GraphQL API plugin for WordPress, and a website builder"
              },
              {
                "id": "MDEwOlJlcG9zaXRvcnkxODQ1MzE5NzA=",
                "name": "PoP-API-WP",
                "description": "Bootstrap a PoP API for WordPress"
              },
              {
                "id": "MDEwOlJlcG9zaXRvcnkxOTYwOTk0MzQ=",
                "name": "leoloso.com",
                "description": "My personal site, based on Hylia (https://hylia.website)"
              }
            ]
          }
        }
      }
    }
  }
}

同じHTTPリクエストを繰り返し実行する必要がある場合は、@cache ディレクティブ(Field Resolution Caching 拡張機能が提供)を使用して、結果を指定した時間だけディスクに保存することができ、クエリの解決を高速化できます。

このクエリを10秒以内に2回実行すると(@cache(time:) 引数で指定)、2回目はキャッシュされた結果を取得します。これにより外部ホストへの接続が不要になり、処理が速くなります。

query ConnectToGitHub($authorizationToken: String!)
{
  _sendGraphQLHTTPRequest(input:{
    endpoint: "https://api.github.com/graphql",
    query: """    
{
  repositoryOwner(login: "leoloso") {
    url
  }
}
    """,
    options: {
      auth: {
        password: $authorizationToken
      }
    }
  })
    # Cache the response to disk, indicating for how many seconds
    @cache(time: 10)
}

@cache ディレクティブの特徴:

  • _sendJSONObjectItemHTTPRequest_sendGraphQLHTTPRequest を含む、JSONレスポンスを返すすべてのフィールドで動作します
  • 独立しています(つまり、適用されるフィールドのロジックに依存しません)。そのため、HTTPリクエストのメソッドが GET でも POST でも動作します
  • _sendHTTPRequest では動作しません。これは、_sendHTTPRequest が返す HTTPResponse オブジェクトが「一時的な」オブジェクト(つまり、WordPressデータベースに保存されない)であり、現在のリクエスト中にのみ存在するためです

複数のURLからデータを取得する

複数のURLにHTTPリクエストを送信し、同時にすべてのデータを取得できます。

上記で紹介した各HTTPリクエストフィールドには、対応する「複数」フィールドがあります。

  • _sendHTTPRequests
  • _sendJSONObjectItemHTTPRequests
  • _sendJSONObjectCollectionHTTPRequests
  • _sendGraphQLHTTPRequests

これらのフィールドはすべて async 引数を持ち、複数のHTTPリクエストを非同期または同期で実行するかを指定します。

  • 非同期:HTTPリクエストがすべて並行して同時に実行されます
  • 同期:各HTTPリクエストは前のリクエストが完了した後にのみ送信されます

このGraphQLクエリは複数の地域の天気予報データを取得します。

query {
  _sendJSONObjectItemHTTPRequests(inputs: [
    {
      url: "https://api.weather.gov/gridpoints/TOP/31,80/forecast"
    },
    {
      url: "https://api.weather.gov/gridpoints/TOP/41,55/forecast"
    }
  ])
}

...次の結果が得られます。

{
  "data": {
    "_sendJSONObjectItemHTTPRequests": [
      {
        "@context": [
          "https://geojson.org/geojson-ld/geojson-context.jsonld",
          {
            "@version": "1.1",
            "wx": "https://api.weather.gov/ontology#",
            "geo": "http://www.opengis.net/ont/geosparql#",
            "unit": "http://codes.wmo.int/common/unit/",
            "@vocab": "https://api.weather.gov/ontology#"
          }
        ],
        "type": "Feature",
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -97.137207,
                39.7444372
              ],
              [
                -97.1367549,
                39.7223799
              ],
              [
                -97.1080809,
                39.7227252
              ],
              [
                -97.10852700000001,
                39.7447825
              ],
              [
                -97.137207,
                39.7444372
              ]
            ]
          ]
        },
        "properties": {
          "updated": "2023-07-13T05:39:07+00:00",
          "units": "us",
          "forecastGenerator": "BaselineForecastGenerator",
          "generatedAt": "2023-07-13T06:44:24+00:00",
          "updateTime": "2023-07-13T05:39:07+00:00",
          "validTimes": "2023-07-12T23:00:00+00:00/P7DT2H",
          "elevation": {
            "unitCode": "wmoUnit:m",
            "value": 456.8952
          },
          "periods": [
            {
              "number": 1,
              "name": "Overnight",
              "startTime": "2023-07-13T01:00:00-05:00",
              "endTime": "2023-07-13T06:00:00-05:00",
              "isDaytime": false,
              "temperature": 68,
              "temperatureUnit": "F",
              "temperatureTrend": null,
              "probabilityOfPrecipitation": {
                "unitCode": "wmoUnit:percent",
                "value": null
              },
              "dewpoint": {
                "unitCode": "wmoUnit:degC",
                "value": 21.666666666666668
              },
              "relativeHumidity": {
                "unitCode": "wmoUnit:percent",
                "value": 100
              },
              "windSpeed": "5 mph",
              "windDirection": "NE",
              "icon": "https://api.weather.gov/icons/land/night/few?size=medium",
              "shortForecast": "Mostly Clear",
              "detailedForecast": "Mostly clear, with a low around 68. Northeast wind around 5 mph."
            },
            {
              "number": 2,
              "name": "Thursday",
              "startTime": "2023-07-13T06:00:00-05:00",
              "endTime": "2023-07-13T18:00:00-05:00",
              "isDaytime": true,
              "temperature": 90,
              "temperatureUnit": "F",
              "temperatureTrend": null,
              "probabilityOfPrecipitation": {
                "unitCode": "wmoUnit:percent",
                "value": null
              },
              "dewpoint": {
                "unitCode": "wmoUnit:degC",
                "value": 21.11111111111111
              },
              "relativeHumidity": {
                "unitCode": "wmoUnit:percent",
                "value": 100
              },
              "windSpeed": "5 to 10 mph",
              "windDirection": "NE",
              "icon": "https://api.weather.gov/icons/land/day/sct?size=medium",
              "shortForecast": "Mostly Sunny",
              "detailedForecast": "Mostly sunny, with a high near 90. Northeast wind 5 to 10 mph."
            },
            // ...
          ]
        }
      },
      {
        "@context": [
          "https://geojson.org/geojson-ld/geojson-context.jsonld",
          {
            "@version": "1.1",
            "wx": "https://api.weather.gov/ontology#",
            "geo": "http://www.opengis.net/ont/geosparql#",
            "unit": "http://codes.wmo.int/common/unit/",
            "@vocab": "https://api.weather.gov/ontology#"
          }
        ],
        "type": "Feature",
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -96.8406778,
                39.1956467
              ],
              [
                -96.8402904,
                39.1735282
              ],
              [
                -96.811767,
                39.1738261
              ],
              [
                -96.8121485,
                39.1959446
              ],
              [
                -96.8406778,
                39.1956467
              ]
            ]
          ]
        },
        "properties": {
          "updated": "2023-07-13T05:39:07+00:00",
          "units": "us",
          "forecastGenerator": "BaselineForecastGenerator",
          "generatedAt": "2023-07-13T07:07:02+00:00",
          "updateTime": "2023-07-13T05:39:07+00:00",
          "validTimes": "2023-07-12T23:00:00+00:00/P7DT2H",
          "elevation": {
            "unitCode": "wmoUnit:m",
            "value": 403.86
          },
          "periods": [
            {
              "number": 1,
              "name": "Overnight",
              "startTime": "2023-07-13T02:00:00-05:00",
              "endTime": "2023-07-13T06:00:00-05:00",
              "isDaytime": false,
              "temperature": 69,
              "temperatureUnit": "F",
              "temperatureTrend": null,
              "probabilityOfPrecipitation": {
                "unitCode": "wmoUnit:percent",
                "value": null
              },
              "dewpoint": {
                "unitCode": "wmoUnit:degC",
                "value": 22.22222222222222
              },
              "relativeHumidity": {
                "unitCode": "wmoUnit:percent",
                "value": 97
              },
              "windSpeed": "5 to 10 mph",
              "windDirection": "NE",
              "icon": "https://api.weather.gov/icons/land/night/few?size=medium",
              "shortForecast": "Mostly Clear",
              "detailedForecast": "Mostly clear, with a low around 69. Northeast wind 5 to 10 mph."
            },
            {
              "number": 2,
              "name": "Thursday",
              "startTime": "2023-07-13T06:00:00-05:00",
              "endTime": "2023-07-13T18:00:00-05:00",
              "isDaytime": true,
              "temperature": 93,
              "temperatureUnit": "F",
              "temperatureTrend": null,
              "probabilityOfPrecipitation": {
                "unitCode": "wmoUnit:percent",
                "value": null
              },
              "dewpoint": {
                "unitCode": "wmoUnit:degC",
                "value": 22.22222222222222
              },
              "relativeHumidity": {
                "unitCode": "wmoUnit:percent",
                "value": 100
              },
              "windSpeed": "5 to 10 mph",
              "windDirection": "NE",
              "icon": "https://api.weather.gov/icons/land/day/sct?size=medium",
              "shortForecast": "Mostly Sunny",
              "detailedForecast": "Mostly sunny, with a high near 93. Northeast wind 5 to 10 mph."
            },
            // ...
          ]
        }
      }
    ]
  }
}

APIレスポンスからデータを抽出する

MailchimpのAPIに戻り、レスポンスからすべてのメールアドレスの一覧を抽出してみましょう。これらは members リストの各アイテムの email_address プロパティの下に含まれています。

{
  "data": {
    "_sendJSONObjectItemHTTPRequest": {
      "members": [
        {
          "email_address": "vinesh@yahoo.com",
          // ...
        },
        {
          "email_address": "thiago@hotmail.com",
          // ...
        },
        // ...
      ]
    }
  }
}

Field Value Iteration and Manipulation 拡張機能は、配列またはオブジェクトの内部要素を反復処理し、それらの要素の下でネストされたディレクティブを適用するコンポーザブルディレクティブを提供します。

  • @underArrayItem: 配列から特定のアイテムを操作する
  • @underJSONObjectProperty: JSONオブジェクトから特定のエントリを操作する
  • @underEachArrayItem: 配列のすべてのアイテムを操作する
  • @underEachJSONObjectProperty: JSONオブジェクトのすべてのエントリを操作する

このGraphQLクエリは各 email_address プロパティに移動し、その値をダイナミック変数 $mailchimpListMemberEmails にエクスポートします。

query GetDataFromMailchimp {
  mailchimpListMembersJSONObject: _sendJSONObjectItemHTTPRequest(input: {
    url: "https://us7.api.mailchimp.com/3.0/lists/{LIST_ID}/members",
    method: GET,
    options: {
      auth: {
        username: "{USER}",
        password: "{API_TOKEN}"
      }
    }
  })
    @underJSONObjectProperty(by: { key: "members"})
      @underEachArrayItem
        @underJSONObjectProperty(by: { key: "email_address"})
          @export(as: "mailchimpListMemberEmails")
}

ダイナミック変数の値を出力することでエントリを確認できます。

query PrintMailchimpSubscriberEmails
  @depends(on: "GetDataFromMailchimp")
{
  mailchimpListMemberEmails: _echo(value: $mailchimpListMemberEmails)
}

...次の結果が得られます。

{
  "data": {
    "mailchimpListMembersJSONObject": {
      // ...
    },
    "mailchimpListMemberEmails": [
      "vinesh@yahoo.com",
      "thiago@hotmail.com",
      // ...
    ]
  }
}

ダイナミック変数 $mailchimpListMemberEmails はリストですが、@export には type: LIST 引数がないことに注目してください。

これは、@export@underEachArrayItem(または @underEachJSONObjectProperty)の下にネストされている場合、エクスポートされた値はすでに配列になるためです。

MailchimpサブスクライバーとWebサイトユーザーのデータを組み合わせる

Mailchimpのサブスクライバーがウェブサイトにもユーザーアカウントを持っており、メールアドレスが両方のアプリケーションの共通IDであると仮定しましょう。

そうすれば、Mailchimpから取得したメールアドレス(現在はダイナミック変数 $mailchimpListMemberEmails に格納されている)を使用して、サイトに保存されている対応するユーザーデータを取得できます。

query GetUsersUsingMailchimpSubscriberEmails
  @depends(on: "GetDataFromMailchimp")
{
  users(filter: { searchBy: { emails: $mailchimpListMemberEmails } } ) {
    id
    name
    email
  }
}

レスポンスは次のようになります。

{
  "data": {
    "mailchimpListMembersJSONObject": {
      // ...
    },
    "users": [
      {
        "id": 88,
        "name": "Vinesh Munak",
        "email": "vinesh@yahoo.com"
      },
      {
        "id": 705,
        "name": "Thiago Barbossa",
        "email": "thiago@hotmail.com"
      }
    ]
  }
}

ユーザーを取得した後は、任意の操作を適用できます(データを更新するミューテーションの実行、メールの送信など)。