Lekcja 19: Pobieranie danych z zewnętrznego API
Rozszerzenie HTTP Client umożliwia wykonywanie żądań HTTP do serwera WWW.
Ta lekcja samouczka pokazuje, jak pobierać dane z zewnętrznego API, poprzez:
- Pobieranie członków listy e-mail z API REST Mailchimp, wyodrębnianie ich adresów e-mail i wykonywanie operacji na tych danych
- Pobieranie repozytoriów z API GraphQL GitHub
Wykonywanie żądania HTTP
Dokumentacja API Mailchimp wyjaśnia, że musimy wysłać żądanie GET do API REST, aby pobrać dane członków listy e-mail:
curl --request GET \
--url 'https://us7.api.mailchimp.com/3.0/lists/{LIST_ID}/members' \
--user 'username:password'Zreplikujmy to w Gato GraphQL.
Wykonujemy żądanie HTTP za pomocą globalnego pola _sendHTTPRequest (dostarczanego przez rozszerzenie HTTP Client):
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")
}
}Pole _sendHTTPRequest zwraca obiekt typu HTTPResponse. Po wykonaniu query, zauważ, że pole body (typu String) zawiera surową zawartość odpowiedzi:
{
"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"
}
}
}Ponieważ content-type odpowiedzi to application/json, możemy przekształcić surową zawartość body z String na JSONObject za pomocą pola _strDecodeJSONObject (z rozszerzenia PHP Functions Via Schema):
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)
}
}Body jest teraz dostępne jako obiekt 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": [
{
// ...
},
// ...
]
}
}
}
}Łączenie z API REST
HTTP Client dostarcza również pola funkcji, które już obsługują odpowiedzi o content-type application/json, co czyni je odpowiednimi do łączenia z API REST:
_sendJSONObjectItemHTTPRequest: Gdy zawartość dotyczy pojedynczego obiektu JSON_sendJSONObjectCollectionHTTPRequest: Gdy zawartość dotyczy kolekcji obiektów JSON
Te pola już konwertują odpowiedź na JSONObject lub [JSONObject].
Te pola oczekują, że kod statusu odpowiedzi będzie oznaczał sukces (tj. w zakresie 200-299, np. 200, 201 lub 202), co umożliwia im bezpośrednie zwrócenie JSONObject zawierającego body odpowiedzi zdekodowane jako JSON.
Gdy tak nie jest, odpowiedź GraphQL będzie zawierać odpowiedni błąd.
Na przykład, podczas pobierania nieistniejącego posta z endpointu /wp-json/wp/v2/posts/{postId}/ WP REST API, odpowiedź będzie:
{
"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
}
}Jeśli nie chcemy traktować żadnego kodu statusu innego niż 200s (np. 302, 404 lub 500) jako błąd, musimy użyć pola _sendHTTPRequest.
Adaptując poprzednią query:
query {
_sendJSONObjectItemHTTPRequest(input: {
url: "https://us7.api.mailchimp.com/3.0/lists/{LIST_ID}/members",
method: GET,
options: {
auth: {
username: "{USER}",
password: "{API_TOKEN}"
}
}
})
}...daje tę odpowiedź:
{
"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": [
{
// ...
},
// ...
]
}
}
}Łączenie z WP REST API, zarówno z zewnętrznego serwera, jak i z tego samego serwisu, przebiega według tej samej procedury.
Na przykład, ta query GraphQL łączy się z WP REST API lokalnego serwisu w trybie ?context=edit (dla którego musi podać dane uwierzytelniające application password):
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
}
}
})
}Przekazując te zmienne:
{
"postId": 1,
"username": "{username}",
"applicationPassword": "{application password}"
}...odpowiedź to:
{
"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": {
// ...
}
}
}
}Łączenie z API GraphQL
HTTP Client dostarcza również pole funkcji umożliwiające wygodne łączenie z API GraphQL.
Pole _sendGraphQLHTTPRequest przyjmuje dane wejściowe oczekiwane przez GraphQL (query, zmienne i nazwę operacji), wykonuje query GraphQL względem podanego endpointu i konwertuje odpowiedź na JSONObject.
Ta query łączy się z API GraphQL GitHub i pobiera listę repozytoriów dla wskazanego właściciela:
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
}
}
})
}Przekazując te variables:
{
"authorizationToken": "{ GITHUB ACCESS TOKEN }",
"login": "leoloso"
}...daje tę odpowiedź:
{
"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)"
}
]
}
}
}
}
}
}Jeśli musimy wielokrotnie wykonywać to samo żądanie HTTP, możemy użyć dyrektywy @cache (dostarczanej przez rozszerzenie Field Resolution Caching), aby przechowywać wynik na dysku przez żądany czas, przyspieszając w ten sposób rozwiązywanie query.
Wykonując tę query dwukrotnie w ciągu 10 sekund (zgodnie ze wskazaniem przez argument @cache(time:)), za drugim razem zostanie pobrany wynik z cache; sprawi to, że będzie szybsza, ponieważ nie będzie łączyć się z zewnętrznym hostem:
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)
}Dyrektywa @cache:
- Działa z dowolnym z pól zwracających odpowiedź JSON, w tym
_sendJSONObjectItemHTTPRequesti_sendGraphQLHTTPRequest - Jest niezależna (tzn. nie przejmuje się logiką pól, w których jest stosowana), dlatego działa niezależnie od tego, czy metoda żądania HTTP to
GETczyPOST - Nie działa z
_sendHTTPRequest, ponieważ obiektHTTPResponse, który zwraca, jest obiektem "przejściowym" (tzn. nie jest przechowywany w bazie danych WordPress), który żyje tylko podczas bieżącego żądania
Pobieranie danych z wielu URL-i
Możemy wysyłać żądania HTTP do wielu URL-i, pobierając dane ze wszystkich naraz.
Każde z powyższych pól żądania HTTP ma odpowiadające mu pole "wielokrotne":
_sendHTTPRequests_sendJSONObjectItemHTTPRequests_sendJSONObjectCollectionHTTPRequests_sendGraphQLHTTPRequests
Wszystkie te pola mają argument async, aby wskazać, czy wielokrotne żądania HTTP mają być wykonywane asynchronicznie czy synchronicznie:
- Asynchronicznie: Żądania HTTP są wykonywane wszystkie razem, równolegle
- Synchronicznie: Każde żądanie HTTP jest wysyłane dopiero po zakończeniu poprzedniego
Ta query GraphQL pobiera dane prognozy pogody dla wielu regionów:
query {
_sendJSONObjectItemHTTPRequests(inputs: [
{
url: "https://api.weather.gov/gridpoints/TOP/31,80/forecast"
},
{
url: "https://api.weather.gov/gridpoints/TOP/41,55/forecast"
}
])
}...dając:
{
"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."
},
// ...
]
}
}
]
}
}Wyodrębnianie danych z odpowiedzi API
Wracając do API Mailchimp, wyodrębnijmy listę wszystkich adresów e-mail z odpowiedzi. Są one zawarte we właściwości email_address każdego elementu listy members:
{
"data": {
"_sendJSONObjectItemHTTPRequest": {
"members": [
{
"email_address": "vinesh@yahoo.com",
// ...
},
{
"email_address": "thiago@hotmail.com",
// ...
},
// ...
]
}
}
}Rozszerzenie Field Value Iteration and Manipulation dostarcza dyrektywy kompozytowe, które iterują po wewnętrznych elementach tablic lub obiektów i stosują zagnieżdżone dyrektywy do tych elementów:
@underArrayItem: Operuje na określonym elemencie tablicy@underJSONObjectProperty: Operuje na określonym wpisie obiektu JSON@underEachArrayItem: Operuje na wszystkich elementach tablicy@underEachJSONObjectProperty: Operuje na wszystkich wpisach obiektu JSON
Ta query GraphQL nawiguje do każdej z właściwości email_address i eksportuje ich wartość do zmiennej dynamicznej $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")
}Możemy zwizualizować wpisy, drukując wartość zmiennej dynamicznej:
query PrintMailchimpSubscriberEmails
@depends(on: "GetDataFromMailchimp")
{
mailchimpListMemberEmails: _echo(value: $mailchimpListMemberEmails)
}...dając:
{
"data": {
"mailchimpListMembersJSONObject": {
// ...
},
"mailchimpListMemberEmails": [
"vinesh@yahoo.com",
"thiago@hotmail.com",
// ...
]
}
}Zauważ, że mimo iż zmienna dynamiczna $mailchimpListMemberEmails jest listą, @export nie ma argumentu type: LIST.
Dzieje się tak dlatego, że zawsze gdy @export jest zagnieżdżony poniżej @underEachArrayItem (lub @underEachJSONObjectProperty), eksportowana wartość będzie już tablicą.
Łączenie danych subskrybentów Mailchimp i użytkowników serwisu
Powiedzmy, że nasi subskrybenci Mailchimp mają również konto użytkownika w naszym serwisie, a ich adres e-mail jest wspólnym identyfikatorem dla obu aplikacji.
Możemy wtedy użyć adresów e-mail pobranych z Mailchimp (teraz przechowywanych w zmiennej dynamicznej $mailchimpListMemberEmails), aby pobrać odpowiednie dane użytkownika przechowywane w naszym serwisie:
query GetUsersUsingMailchimpSubscriberEmails
@depends(on: "GetDataFromMailchimp")
{
users(filter: { searchBy: { emails: $mailchimpListMemberEmails } } ) {
id
name
email
}
}Odpowiedź będzie:
{
"data": {
"mailchimpListMembersJSONObject": {
// ...
},
"users": [
{
"id": 88,
"name": "Vinesh Munak",
"email": "vinesh@yahoo.com"
},
{
"id": 705,
"name": "Thiago Barbossa",
"email": "thiago@hotmail.com"
}
]
}
}Po pobraniu użytkowników możemy zastosować na nich dowolną pożądaną operację (wykonać mutację w celu aktualizacji ich danych, wysłać e-mail itp.).