บทเรียนที่ 5: การปรับแต่งเนื้อหาสำหรับผู้ใช้ที่แตกต่างกัน
เราสามารถดึงค่าที่ตอบกลับในฟิลด์ให้แตกต่างกันได้ตามข้อมูลบางส่วนที่ query มา เช่น บทบาทของผู้ใช้ที่ล็อกอินอยู่
GraphQL query เพื่อปรับแต่งเนื้อหาสำหรับผู้ใช้ที่แตกต่างกัน
GraphQL query นี้จะดึงเนื้อหาของโพสต์ และเพิ่มลิงก์ "Edit this post" ไว้ที่ท้ายเนื้อหาสำหรับผู้ใช้ที่เป็น admin เท่านั้น:
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable(enabled: false)
{
isAdminUser: _echo(value: false)
@export(as: "isAdminUser")
@remove
}
query ExportConditionalVariables
@depends(on: "InitializeDynamicVariables")
{
me {
roleNames @remove
isAdminUser: _inArray(
value: "administrator",
array: $__roleNames
)
@export(as: "isAdminUser")
}
}
query RetrieveContentForAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
post(by: { id : $postId }) {
originalContent: content @remove
wpAdminEditURL @remove
content: _sprintf(
string: "%s<p><a href=\"%s\">%s</a></p>",
values: [
$__originalContent,
$__wpAdminEditURL,
"(Admin only) Edit post"
]
)
}
}
query RetrieveContentForNonAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
post(by: { id : $postId }) {
content
}
}
query ExecuteAll
@depends(on: [
"RetrieveContentForAdminUser",
"RetrieveContentForNonAdminUser"
])
{
id @remove
}สำหรับผู้ใช้ที่เป็น admin ค่าที่ตอบกลับจะเป็น:
{
"data": {
"user": {
"isAdminUser": true
},
"post": {
"content": "\n<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!<\/p>\n<p><a href=\"https:\/\/mysite.com\/wp-admin\/post.php?post=1&action=edit\">(Admin only) Edit post<\/a><\/p>"
}
}
}สำหรับผู้ใช้ที่ไม่ใช่ admin ค่าที่ตอบกลับจะเป็น:
{
"data": {
"user": {
"isAdminUser": false
},
"post": {
"content": "\n<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!<\/p>\n"
}
}
}การให้ GraphQL server คำนวณค่าที่ฟิลด์ต้องการแบบไดนามิก (โดยพิจารณาจากเงื่อนไขที่เป็นไปได้ทั้งหมด):
- ทำให้ตรรกะของแอปพลิเคชันเรียบง่ายขึ้น เพราะมีแหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียว โค้ดเป็น DRY และไคลเอนต์ไม่จำเป็นต้องเขียนตรรกะที่สอดคล้องกันนั้นเองอีกต่อไป
- ทำให้แอปพลิเคชันเชื่อถือได้มากขึ้น โดยเฉพาะเมื่อมีไคลเอนต์หลายตัวเข้าถึงข้อมูลจาก server เพราะการนำตรรกะเดียวกันไปใช้งานในแบบที่ต่างกันอาจไม่เหมือนกัน ซึ่งอาจนำไปสู่บั๊กได้ (ยิ่งเป็นเช่นนั้นเมื่อไคลเอนต์ใช้เทคโนโลยีที่แตกต่างกัน เช่น JavaScript สำหรับเว็บไซต์, Java สำหรับแอป Android, Swift สำหรับแอป iPhone และอื่น ๆ)
ทีละขั้นตอน: การสร้าง GraphQL query
ด้านล่างคือการวิเคราะห์โดยละเอียดว่า query นี้ทำงานอย่างไร
การตรวจสอบว่าผู้ใช้เป็น admin หรือไม่
query นี้ตรวจสอบว่าผู้ใช้ที่ล็อกอินอยู่มีบทบาท "administrator" หรือไม่ และ export เงื่อนไขนี้ไว้ในตัวแปรไดนามิก $isAdminUser:
query
{
me {
roleNames
isAdminUser: _inArray(
value: "administrator",
array: $__roleNames
)
@export(as: "isAdminUser")
}
}การเรียกใช้ operation แบบมีเงื่อนไข
เมื่อเปิดใช้งาน Multiple Query Execution แล้ว ไดเรกทีฟ @include และ @skip ก็สามารถนำไปใช้กับ operation ได้เช่นกัน วิธีนี้ทำให้เราเลือกได้ว่าจะเรียกใช้ operation หรือไม่ ตามค่าของตัวแปรไดนามิกบางตัว
ใน query ด้านล่าง จะมีการเรียกใช้เพียง operation เดียวจากสอง operation:
RetrieveContentForAdminUserจะถูกเรียกใช้เมื่อ$isAdminUserเป็นtrueเท่านั้นRetrieveContentForNonAdminUserจะถูกเรียกใช้เมื่อ$isAdminUserเป็นfalseเท่านั้น
query RetrieveContentForAdminUser
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
# ...
}
query RetrieveContentForNonAdminUser
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
# ...
}มาให้ค่าที่ตอบกลับสองแบบที่แตกต่างกันสำหรับฟิลด์ content ของโพสต์ ขึ้นอยู่กับว่าผู้ใช้เป็น admin หรือไม่:
- operation แรกใช้
contentเป็น alias และคำนวณค่าของฟิลด์แบบไดนามิก โดยนำฟิลด์originalContentและwpAdminEditURLมาต่อกันผ่าน_sprintf - operation ที่สองดึงฟิลด์
contentมาโดยตรง
query RetrieveContentForAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
post(by: { id : $postId }) {
originalContent: content
wpAdminEditURL
content: _sprintf(
string: "%s<p><a href=\"%s\">%s</a></p>",
values: [
$__originalContent,
$__wpAdminEditURL,
"(Admin only) Edit post"
]
)
}
}
query RetrieveContentForNonAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
post(by: { id : $postId }) {
content
}
}การเพิ่ม operation ที่จะถูกเรียกใช้
ตอนนี้เรามีสอง operation ที่อาจถูกเรียกใช้ได้ แต่เราระบุ ?operationName=... ได้เพียงค่าเดียวเมื่อเรียกใช้ query
ดังนั้น เราจึงเพิ่ม operation ExecuteAll ที่ขึ้นอยู่กับทั้ง RetrieveContentForAdminUser และ RetrieveContentForNonAdminUser โดยมีฟิลด์อย่างง่าย id อยู่ภายใน (เพราะเราต้อง query บางอย่างใน operation):
query ExecuteAll
@depends(on: [
"RetrieveContentForAdminUser",
"RetrieveContentForNonAdminUser"
])
{
id
}การเรียก endpoint ด้วย ?operationName=ExecuteAll จะโหลดทั้งสอง operation แต่จะมีเพียง operation เดียวเท่านั้นที่ถูกเรียกใช้งานจริง
การลบข้อมูลที่ไม่จำเป็นออก
ขั้นตอนสุดท้ายคือการลบฟิลด์ทั้งหมดที่เป็นฟิลด์เสริม (ซึ่งเราไม่จำเป็นต้องแสดงผลลัพธ์ในค่าที่ตอบกลับ) ออกด้วย @remove
GraphQL query ที่รวมเข้าด้วยกันแล้วคือ:
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable(enabled: false)
{
isAdminUser: _echo(value: false)
@export(as: "isAdminUser")
@remove
}
query ExportConditionalVariables
@depends(on: "InitializeDynamicVariables")
{
me {
roleNames @remove
isAdminUser: _inArray(
value: "administrator",
array: $__roleNames
)
@export(as: "isAdminUser")
}
}
query RetrieveContentForAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
post(by: { id : $postId }) {
originalContent: content @remove
wpAdminEditURL @remove
content: _sprintf(
string: "%s<p><a href=\"%s\">%s</a></p>",
values: [
$__originalContent,
$__wpAdminEditURL,
"(Admin only) Edit post"
]
)
}
}
query RetrieveContentForNonAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
post(by: { id : $postId }) {
content
}
}
query ExecuteAll
@depends(on: [
"RetrieveContentForAdminUser",
"RetrieveContentForNonAdminUser"
])
{
id @remove
}