บทเรียนที่ 25: การแปลงข้อมูลจาก API ภายนอก
บทเรียนในทูทอเรียลนี้สาธิตตัวอย่างการปรับเปลี่ยนการตอบกลับจาก API ภายนอกให้เป็นรูปแบบใดก็ตามที่เราต้องการ
การเพิ่มค่าเริ่มต้นและพร็อพเพอร์ตี้เพิ่มเติมให้แต่ละรายการ
REST API endpoint newapi.getpop.org/wp-json/wp/v2/users/?_fields=id,name,url จะส่งคืนข้อมูลผู้ใช้ โดยผู้ใช้บางรายมีพร็อพเพอร์ตี้ url ว่างเปล่า:
[
{
"id": 1,
"name": "leo",
"url": "https://leoloso.com"
},
{
"id": 7,
"name": "Test",
"url": ""
},
{
"id": 2,
"name": "Theme Demos",
"url": ""
}
]GraphQL query ด้านล่างนี้แปลงการตอบกลับนี้:
- เพิ่ม URL เริ่มต้นให้กับผู้ใช้ที่มีพร็อพเพอร์ตี้
urlว่างเปล่า - เพิ่มพร็อพเพอร์ตี้
linkให้แต่ละรายการผู้ใช้ (ประกอบขึ้นจากค่าชื่อและ URL ของผู้ใช้)
query {
# Retrieve data from the external API
usersWithLinkAndDefaultURL: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/wp/v2/users/?_fields=id,name,url"
}
)
# Set a default URL for users without any
@underEachArrayItem
@underJSONObjectProperty(
by: {
key: "url"
}
)
@default(
value: "https://mysite.com"
condition: IS_EMPTY
)
# Add a new "link" entry on the JSON object
@underEachArrayItem(
affectDirectivesUnderPos: [1, 2, 3, 4],
passValueOnwardsAs: "userListItem"
)
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "name"
}
},
passOnwardsAs: "userName"
)
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "url"
}
},
passOnwardsAs: "userURL"
)
@applyField(
name: "_sprintf",
arguments: {
string: "<a href=\"%s\">%s</a>",
values: [$userURL, $userName]
},
passOnwardsAs: "userLink"
)
@applyField(
name: "_objectAddEntry",
arguments: {
object: $userListItem,
key: "link",
value: $userLink
},
setResultInResponse: true
)
}การตอบกลับคือ:
{
"data": {
"usersWithLinkAndDefaultURL": [
{
"id": 1,
"name": "leo",
"url": "https://leoloso.com",
"link": "<a href=\"https://leoloso.com\">leo</a>"
},
{
"id": 7,
"name": "Test",
"url": "https://mysite.com",
"link": "<a href=\"https://mysite.com\">Test</a>"
},
{
"id": 2,
"name": "Theme Demos",
"url": "https://mysite.com",
"link": "<a href=\"https://mysite.com\">Theme Demos</a>"
}
]
}
}Composable directives สามารถซ้อน (nest) directive หนึ่งตัวหรือมากกว่าไว้ภายในได้ เมื่อซ้อนมากกว่าหนึ่งตัว เราจะระบุสิ่งนี้ผ่านอาร์กิวเมนต์ affectDirectivesUnderPos ซึ่งบรรจุตำแหน่งสัมพัทธ์จาก directive นั้นไปยัง directive ที่ซ้อนอยู่
ใน GraphQL query ด้านบน directive @underEachArrayItem (จัดเตรียมโดยเอ็กซ์เทนชัน Field Value Iteration and Manipulation) เป็น composable directive ในการปรากฏครั้งแรก มันซ้อน directive เพียงตัวเดียว และอาร์กิวเมนต์ affectDirectivesUnderPos สามารถละเว้นได้:
@underEachArrayItem
@underJSONObjectProperty(
# ...
)(อนึ่ง สังเกตว่า @underJSONObjectProperty ก็เป็น composable directive เช่นกัน โดยซ้อน directive @default ไว้)
ในการปรากฏครั้งที่สอง มันซ้อน directive 4 ตัวที่อยู่ทางขวา ตามที่ระบุด้วยอาร์กิวเมนต์ affectDirectivesUnderPos ที่มีค่า [1, 2, 3, 4]:
@underEachArrayItem(
affectDirectivesUnderPos: [1, 2, 3, 4],
# ...
)
@applyField(
name: "_objectProperty",
# ...
)
@applyField(
name: "_objectProperty",
# ...
)
@applyField(
name: "_sprintf",
# ...
)
@applyField(
name: "_objectAddEntry",
# ...
)🔥 เคล็ดลับ:
Directive @applyField (จัดเตรียมโดยเอ็กซ์เทนชัน Field on Field) มีปลายทางที่เป็นไปได้สองแห่งสำหรับผลลัพธ์ของมัน:
- การระบุอาร์กิวเมนต์
passOnwardsAs: "someVariableName"จะกำหนดค่าใหม่ให้กับตัวแปรไดนามิก$someVariableNameซึ่ง directive ที่ซ้อนอยู่ถัดไปสามารถอ่านค่านี้ได้:
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "name"
}
},
passOnwardsAs: "userName"
)- การระบุอาร์กิวเมนต์
setResultInResponse: trueจะกำหนดค่าใหม่กลับเข้าไปยังฟิลด์อีกครั้ง (ดังนั้นจึงเป็นการแก้ไขการตอบกลับ):
@applyField(
name: "_objectAddEntry",
arguments: {
object: $userListItem,
key: "link",
value: $userLink
},
setResultInResponse: true
)การสกัดพร็อพเพอร์ตี้เฉพาะออกจาก JSON object
REST API endpoint newapi.getpop.org/wp-json/newsletter/v1/subscriptions จะส่งคืนคอลเลกชันของข้อมูลการสมัครรับอีเมล ซึ่งรวมถึงอีเมลและภาษาของผู้สมัครรับข้อมูล:
[
{
"email": "abracadabra@ganga.com",
"lang": "de"
},
{
"email": "longon@caramanon.com",
"lang": "es"
},
{
"email": "rancotanto@parabara.com",
"lang": "en"
},
{
"email": "quezarapadon@quebrulacha.net",
"lang": "fr"
},
{
"email": "test@test.com",
"lang": "de"
},
{
"email": "emilanga@pedrola.com",
"lang": "fr"
}
]GraphQL query นี้พิมพ์เฉพาะอีเมลจากการตอบกลับของ API โดยการสกัดพร็อพเพอร์ตี้ email ออกจากแต่ละรายการและแทนที่ค่าของฟิลด์ด้วยค่านั้น:
query {
emails: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/newsletter/v1/subscriptions"
}
)
@underEachArrayItem(
passValueOnwardsAs: "userEntry"
)
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "email"
}
}
setResultInResponse: true
)
}การตอบกลับคือ:
{
"data": {
"emails": [
"abracadabra@ganga.com",
"longon@caramanon.com",
"rancotanto@parabara.com",
"quezarapadon@quebrulacha.net",
"test@test.com",
"emilanga@pedrola.com"
]
}
}การแก้ไขค่าฟิลด์แบบมีเงื่อนไข
ตัวอย่างนี้ต่อเนื่องจากตัวอย่างก่อนหน้า และเพิ่มการแปลงรูปแบบของอีเมลในการตอบกลับด้วย
GraphQL query ด้านล่างนี้สกัดอีเมลออกจากการตอบกลับของ API และแปลงเป็นตัวพิมพ์ใหญ่สำหรับผู้ใช้ที่มีภาษาเป็นภาษาอังกฤษหรือภาษาเยอรมัน ผ่าน composable directive @if (จัดเตรียมโดยเอ็กซ์เทนชัน Conditional Field Manipulation):
query {
# Retrieve data from a REST API endpoint
userEntries: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/newsletter/v1/subscriptions"
}
)
@remove
emails: _echo(value: $__userEntries)
# Iterate all the entries, passing every entry
# (under the dynamic variable $userEntry)
# to each of the next 4 directives
@underEachArrayItem(
passValueOnwardsAs: "userEntry"
affectDirectivesUnderPos: [1, 2, 3, 4]
)
# Extract property "lang" from the entry
# via the functionality field `_objectProperty`,
# and pass it onwards as dynamic variable $userLang
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "lang"
}
}
passOnwardsAs: "userLang"
)
# Execute functionality field `_inArray` to find out
# if $userLang is either "en" or "de", and place the
# result under dynamic variable $isSpecialLang
@applyField(
name: "_inArray"
arguments: {
value: $userLang,
array: ["en", "de"]
}
passOnwardsAs: "isSpecialLang"
)
# Extract property "email" from the entry
# and set it back as the value for that entry
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "email"
}
}
setResultInResponse: true
)
# If $isSpecialLang is `true` then execute
# directive `@strUpperCase`
@if(condition: $isSpecialLang)
@strUpperCase
}การตอบกลับคือ:
{
"data": {
"emails": [
"ABRACADABRA@GANGA.COM",
"longon@caramanon.com",
"RANCOTANTO@PARABARA.COM",
"quezarapadon@quebrulacha.net",
"TEST@TEST.COM",
"emilanga@pedrola.com"
]
}
}การดำเนินตรรกะแบบมีเงื่อนไขใน Gato GraphQL สามารถทำให้เป็นแบบไดนามิกได้: โดยการส่งตัวแปรไดนามิกที่ถูกประเมินบนออบเจ็กต์ที่ query ไปยัง @if(condition:) (และไปยัง @unless(condition:) ด้วย) ตรรกะจะถูกดำเนินการหรือไม่ขึ้นอยู่กับเงื่อนไขจากเอนทิตีนั้น
ด้วยวิธีนี้ เราสามารถแก้ไขการตอบกลับสำหรับบางเอนทิตี (และไม่ใช่เอนทิตีอื่น) แบบไดนามิก โดยอิงตามเงื่อนไขต่าง ๆ เช่น:
- โพสต์มีคอมเมนต์หรือไม่?
- คอมเมนต์มีการตอบกลับหรือไม่?
- ผู้ใช้เป็นผู้ดูแลระบบหรือไม่?
- แท็ก/หมวดหมู่ถูกนำไปใช้กับโพสต์ใดหรือไม่?
- ฯลฯ