บทเรียนที่ 3: การทำสำเนาบล็อกโพสต์
การทำสำเนาโพสต์เป็นตัวอย่างของความสามารถของ Gato GraphQL ในการดึง จัดการ และจัดเก็บข้อมูลในเว็บไซต์อีกครั้ง
GraphQL query สำหรับทำสำเนาบล็อกโพสต์
GraphQL query นี้จะทำสำเนาโพสต์ที่ระบุด้วยตัวแปร $postId:
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable(enabled: false)
{
authorID: _echo(value: null)
@export(as: "authorID")
@remove
categoryIDs: _echo(value: [])
@export(as: "categoryIDs")
@remove
featuredImageID: _echo(value: null)
@export(as: "featuredImageID")
@remove
tagIDs: _echo(value: [])
@export(as: "tagIDs")
@remove
}
query GetPostAndExportData($postId: ID!)
@depends(on: "InitializeDynamicVariables")
{
post(by: { id : $postId }) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id @export(as: "authorID")
}
categories {
id @export(as: "categoryIDs", type: LIST)
}
rawContent @export(as: "rawContent")
rawExcerpt @export(as: "excerpt")
featuredImage {
id @export(as: "featuredImageID")
}
tags {
id @export(as: "tagIDs", type: LIST)
}
rawTitle @export(as: "title")
}
}
mutation DuplicatePost
@depends(on: "GetPostAndExportData")
{
createPost(input: {
status: draft,
authorBy: {
id: $authorID
},
categoriesBy: {
ids: $categoryIDs
},
contentAs: {
html: $rawContent
},
excerpt: $excerpt
featuredImageBy: {
id: $featuredImageID
},
tagsBy: {
ids: $tagIDs
},
title: $title
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
post {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}
}ทีละขั้นตอน: การสร้าง GraphQL query
ด้านล่างนี้คือการวิเคราะห์โดยละเอียดว่า query ทำงานอย่างไร
การดึงข้อมูลโพสต์
GraphQL query นี้จะดึงข้อมูลพื้นฐานของโพสต์:
query GetPost($postId: ID!) {
post(by: { id : $postId }) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}เมื่อรัน query (โดยส่งตัวแปร $postId) เข้าไป เรสปอนส์อาจเป็นดังนี้:
{
"data": {
"post": {
"id": 25,
"slug": "public-or-private-api-mode-for-extra-security",
"date": "2020-12-12T04:06:52+00:00",
"author": {
"id": 2
},
"categories": [
{
"id": 4
},
{
"id": 3
},
{
"id": 2
}
],
"rawContent": "<!-- wp:heading -->\n<h2>Verse Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:verse -->\n<pre class=\"wp-block-verse\">Write poetry and other literary expressions honoring all spaces and line-breaks.</pre>\n<!-- /wp:verse -->\n\n<!-- wp:heading -->\n<h2>Table Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:table {\"className\":\"is-style-stripes\"} -->\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td>Row 1 Column 1</td><td>Row 1 Column 2</td></tr><tr><td>Row 2 Column 1</td><td>Row 2 Column 2</td></tr><tr><td>Row 3 Column 1</td><td>Row 3 Column 2</td></tr></tbody></table></figure>\n<!-- /wp:table -->\n\n<!-- wp:heading -->\n<h2>Separator Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:separator -->\n<hr class=\"wp-block-separator\"/>\n<!-- /wp:separator -->\n\n<!-- wp:heading {\"className\":\"has-top-margin\"} -->\n<h2 class=\"has-top-margin\">Spacer Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:spacer -->\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"></div>\n<!-- /wp:spacer -->",
"excerpt": "Verse Block Write poetry and other literary expressions honoring all spaces and line-breaks. Table Block Row 1 Column 1 Row 1 Column 2 Row 2 Column 1 Row 2 Column 2 Row 3 Column 1 Row 3 Column 2 Separator Block Spacer Block",
"featuredImage": {
"id": 362
},
"tags": [
{
"id": 12
},
{
"id": 7
}
],
"title": "Public or Private API mode, for extra security"
}
}
}โปรดสังเกตว่าบางฟิลด์มีไว้สำหรับทำสำเนา (รวมถึงผู้เขียน ชื่อเรื่อง และเนื้อหา) ในขณะที่ฟิลด์อื่น ๆ ไม่ได้ทำสำเนา (เช่น id, slug และวันที่สร้าง)
การทำสำเนาโพสต์: แนวทางที่หนึ่ง
ด้วยส่วนขยาย Multiple Query Execution เราสามารถส่งออกรายการข้อมูลของโพสต์ และนำกลับเข้าไปยัง query หรือ mutation อื่นในเอกสาร GraphQL เดียวกันได้
Multiple Query Execution ช่วยให้เราสามารถรันฟังก์ชันการทำงานที่ซับซ้อนภายในคำขอเดียว และจัดระเบียบตรรกะได้ดียิ่งขึ้นโดยการแบ่งเอกสาร GraphQL ออกเป็นชุดของหน่วยเชิงตรรกะ/อะตอมมิก:
- ไม่มีข้อจำกัดในจำนวนออเปอเรชันที่สามารถเพิ่มเข้าไปในไปป์ไลน์ได้
- ออเปอเรชันใด ๆ สามารถประกาศ dependency ได้มากกว่าหนึ่งรายการ:
query SomeQuery @depends(on: ["SomePreviousOp", "AnotherPreviousOp"]) {
# ...
}- ออเปอเรชันใด ๆ สามารถขึ้นอยู่กับออเปอเรชันอื่น ซึ่งออเปอเรชันนั้นก็ขึ้นอยู่กับออเปอเรชันอื่นอีกได้ (เป็นเช่นนี้ต่อไป):
query ExecuteFirst
# ...
}
query ExecuteSecond @depends(on: ["ExecuteFirst"]) {
# ...
}
query ExecuteThird @depends(on: ["ExecuteSecond"]) {
# ...
}-
เราสามารถรันออเปอเรชันใดก็ได้ในเอกสาร:
?operationName=ExecuteThirdรันExecuteFirst>ExecuteSecond>ExecuteThird?operationName=ExecuteSecondรันExecuteFirst>ExecuteSecond?operationName=ExecuteFirstรันExecuteFirst
-
เมื่อ
@dependsรับออเปอเรชันเพียงรายการเดียว มันสามารถรับStringได้ (แทนที่จะเป็น[String]):
query ExecuteFirst
# ...
}
query ExecuteSecond @depends(on: "ExecuteFirst") {
# ...
}- ออเปอเรชันทั้ง
queryและmutationสามารถขึ้นอยู่กับกันและกันได้:
query GetAndExportData
# ...
}
mutation MutateData @depends(on: "GetAndExportData") {
# ...
}
query CountMutatedResults @depends(on: "MutateData") {
# ...
}- ตัวแปรไดนามิกไม่จำเป็นต้องประกาศในออเปอเรชัน
- ผ่านอินพุต
@export(type:)เราสามารถเลือกรูปแบบเอาต์พุตของข้อมูลที่ส่งออกไปยังตัวแปรไดนามิกได้:SINGLE(ค่าเริ่มต้น): ค่าฟิลด์เดี่ยวLIST: อาร์เรย์ที่มีค่าฟิลด์ของรีซอร์สหลายรายการDICTIONARY: ดิกชันนารีที่มีค่าฟิลด์ของรีซอร์สหลายรายการ โดยมีคีย์:${resource ID}และค่า:${field value}
query ต่อไปนี้สร้างไปป์ไลน์ของสองออเปอเรชันในเอกสาร GraphQL (GetPostAndExportData และ DuplicatePost) ซึ่งสามารถแบ่งปันข้อมูลซึ่งกันและกันได้:
DuplicatePostระบุให้รันGetPostAndExportDataก่อน ผ่านไดเรกทีฟ@dependsGetPostAndExportDataส่งออกข้อมูลผ่านไดเรกทีฟ@exportไปยังตัวแปรไดนามิก- จากนั้น
DuplicatePostจะอ่านตัวแปรไดนามิก และนำไปเป็นอินพุตให้กับ mutationcreatePost
query GetPostAndExportData($postId: ID!) {
post(by: { id : $postId }) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id @export(as: "authorID")
}
categories {
id @export(as: "categoryIDs", type: LIST)
}
rawContent @export(as: "rawContent")
rawExcerpt @export(as: "excerpt")
featuredImage {
id @export(as: "featuredImageID")
}
tags {
id @export(as: "tagIDs", type: LIST)
}
rawTitle @export(as: "title")
}
}
mutation DuplicatePost
@depends(on: "GetPostAndExportData")
{
createPost(input: {
status: draft,
authorBy: {
id: $authorID
},
categoriesBy: {
ids: $categoryIDs
},
contentAs: {
html: $rawContent
},
excerpt: $excerpt
featuredImageBy: {
id: $featuredImageID
},
tagsBy: {
ids: $tagIDs
},
title: $title
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
post {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}
}ในเรสปอนส์ เราสามารถเห็นได้ว่าฟิลด์ของโพสต์ใหม่นั้นเหมือนกันจริง ๆ:
{
"data": {
"post": {
"id": 25,
"slug": "public-or-private-api-mode-for-extra-security",
"date": "2020-12-12T04:06:52+00:00",
"status": "publish",
"author": {
"id": 2
},
"categories": [
{
"id": 4
},
{
"id": 3
},
{
"id": 2
}
],
"rawContent": "<!-- wp:heading -->\n<h2>Verse Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:verse -->\n<pre class=\"wp-block-verse\">Write poetry and other literary expressions honoring all spaces and line-breaks.</pre>\n<!-- /wp:verse -->\n\n<!-- wp:heading -->\n<h2>Table Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:table {\"className\":\"is-style-stripes\"} -->\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td>Row 1 Column 1</td><td>Row 1 Column 2</td></tr><tr><td>Row 2 Column 1</td><td>Row 2 Column 2</td></tr><tr><td>Row 3 Column 1</td><td>Row 3 Column 2</td></tr></tbody></table></figure>\n<!-- /wp:table -->\n\n<!-- wp:heading -->\n<h2>Separator Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:separator -->\n<hr class=\"wp-block-separator\"/>\n<!-- /wp:separator -->\n\n<!-- wp:heading {\"className\":\"has-top-margin\"} -->\n<h2 class=\"has-top-margin\">Spacer Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:spacer -->\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"></div>\n<!-- /wp:spacer -->",
"excerpt": "Verse Block Write poetry and other literary expressions honoring all spaces and line-breaks. Table Block Row 1 Column 1 Row 1 Column 2 Row 2 Column 1 Row 2 Column 2 Row 3 Column 1 Row 3 Column 2 Separator Block Spacer Block",
"featuredImage": {
"id": 362
},
"tags": [
{
"id": 12
},
{
"id": 7
}
],
"title": "Public or Private API mode, for extra security"
},
"createPost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1207,
"slug": "public-or-private-api-mode-for-extra-security-2",
"date": "2023-07-07T02:06:17+00:00",
"status": "draft",
"author": {
"id": 2
},
"categories": [
{
"id": 4
},
{
"id": 3
},
{
"id": 2
}
],
"rawContent": "<!-- wp:heading -->\n<h2>Verse Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:verse -->\n<pre class=\"wp-block-verse\">Write poetry and other literary expressions honoring all spaces and line-breaks.</pre>\n<!-- /wp:verse -->\n\n<!-- wp:heading -->\n<h2>Table Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:table {\"className\":\"is-style-stripes\"} -->\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td>Row 1 Column 1</td><td>Row 1 Column 2</td></tr><tr><td>Row 2 Column 1</td><td>Row 2 Column 2</td></tr><tr><td>Row 3 Column 1</td><td>Row 3 Column 2</td></tr></tbody></table></figure>\n<!-- /wp:table -->\n\n<!-- wp:heading -->\n<h2>Separator Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:separator -->\n<hr class=\"wp-block-separator\"/>\n<!-- /wp:separator -->\n\n<!-- wp:heading {\"className\":\"has-top-margin\"} -->\n<h2 class=\"has-top-margin\">Spacer Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:spacer -->\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"></div>\n<!-- /wp:spacer -->",
"excerpt": "Verse Block Write poetry and other literary expressions honoring all spaces and line-breaks. Table Block Row 1 Column 1 Row 1 Column 2 Row 2 Column 1 Row 2 Column 2 Row 3 Column 1 Row 3 Column 2 Separator Block Spacer Block",
"featuredImage": {
"id": 362
},
"tags": [
{
"id": 12
},
{
"id": 7
}
],
"title": "Public or Private API mode, for extra security"
}
}
}
}ปัญหาของแนวทางที่หนึ่ง
query ข้างต้นจะคืนค่าข้อผิดพลาดเมื่อฟิลด์การเชื่อมต่อว่างเปล่า เนื่องจากตัวแปรไดนามิกจะไม่ถูกส่งออก
ตัวอย่างเช่น เมื่อโพสต์ที่จะทำสำเนาไม่มีภาพเด่น ฟิลด์ featuredImage จะเป็น null ดังนั้น id @export(as: "featuredImageID") จะไม่ถูกรันเลย:
{
post {
featuredImage {
id @export(as: "featuredImageID")
}
}
}เนื่องจากตัวแปรไดนามิก $featuredImageID จะไม่มีอยู่ เรสปอนส์จึงจะให้ข้อผิดพลาด:
{
"errors": [
{
"message": "No value has been exported for dynamic variable 'featuredImageID'",
"locations": [
{
"line": 39,
"column": 22
}
]
}
],
"data": {
// ...
}
}สองแนวทางต่อไปนี้จะจัดการกับปัญหานี้
การทำสำเนาโพสต์: แนวทางที่สอง
ใน Gato GraphQL ฟิลด์การเชื่อมต่อก็จัดเก็บค่าเช่นกัน เมื่อถูกแปลค่าครั้งแรก ฟิลด์เหล่านี้จะมี ID ของรีซอร์สที่ชี้ไป (ไม่ว่าจะเป็น ID ของรีซอร์สที่เชื่อมโยง หรืออาร์เรย์ที่มี ID ของรีซอร์สที่เชื่อมโยง) ต่อมาเมื่อการเชื่อมต่อถูกแปลค่าแล้วเท่านั้น ID จึงจะถูกแทนที่ด้วยอ็อบเจกต์รีซอร์สจริง
ตัวอย่างเช่น ใน query ต่อไปนี้:
{
post {
featuredImage {
id
}
tags {
id
}
}
}...ฟิลด์ featuredImage จะมีค่าเริ่มต้นเป็น 362 (นั่นคือ ID ของภาพเด่น) และฟิลด์ tags จะมีอาร์เรย์ [12, 7] (นั่นคือ ID ของแท็ก)
เมื่อค่าที่จะส่งออกเป็น ID (เช่น $featuredImageID) หรืออาร์เรย์ของ ID (เช่น $tagIDs) เราสามารถใช้ประโยชน์จากคุณลักษณะนี้และส่งออก ID ในฟิลด์การเชื่อมต่อได้เลย
แทนที่จะทำเช่นนี้:
{
post {
featuredImage {
id @export(as: "featuredImageID")
}
tags {
id @export(as: "tagIDs", type: LIST)
}
}
}...เราสามารถทำเช่นนี้ได้:
{
post {
featuredImage @export(as: "featuredImageID") {
id
}
tags @export(as: "tagIDs") {
id
}
}
}(โปรดสังเกตว่าอาร์กิวเมนต์ type: LIST ถูกลบออกเมื่อส่งออก $tagIDs เนื่องจากฟิลด์การเชื่อมต่อเป็นลิสต์อยู่แล้ว)
ตอนนี้ ตัวแปรไดนามิกเหล่านี้จะถูกส่งออกเสมอ โดยมีค่า:
nullสำหรับ$featuredImageIDเมื่อโพสต์ไม่มีภาพเด่น- อาร์เรย์ว่าง
[]สำหรับ$tagIDsเมื่อโพสต์ไม่มีแท็ก
เมื่อปรับ GraphQL query แล้ว จะกลายเป็นดังนี้:
query GetPostAndExportData($postId: ID!) {
post(by: { id : $postId }) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author @export(as: "authorID") {
id
}
categories @export(as: "categoryIDs") {
id
}
rawContent @export(as: "rawContent")
rawExcerpt @export(as: "excerpt")
featuredImage @export(as: "featuredImageID") {
id
}
tags @export(as: "tagIDs") {
id
}
rawTitle @export(as: "title")
}
}
mutation DuplicatePost
@depends(on: "GetPostAndExportData")
{
createPost(input: {
status: draft,
authorBy: {
id: $authorID
},
categoriesBy: {
ids: $categoryIDs
},
contentAs: {
html: $rawContent
},
excerpt: $excerpt
featuredImageBy: {
id: $featuredImageID
},
tagsBy: {
ids: $tagIDs
},
title: $title
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
post {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}
}...ตอนนี้เรสปอนส์ทำงานได้อย่างถูกต้อง:
{
"data": {
"post": {
"id": 23,
"slug": "graphql-or-rest-you-can-have-both",
"date": "2020-12-12T04:04:54+00:00",
"status": "publish",
"author": {
"id": 2
},
"categories": [
{
"id": 1
}
],
"rawContent": "<!-- wp:heading -->\n<h2>Audio Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:audio -->\n<figure class=\"wp-block-audio\"><audio controls src=\"https://freemusicarchive.org/file/music/WFMU/Broke_For_Free/Directionless_EP/Broke_For_Free_-_01_-_Night_Owl.mp3\"></audio></figure>\n<!-- /wp:audio -->\n\n<!-- wp:heading -->\n<h2>Video Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:video -->\n<figure class=\"wp-block-video\"><video controls src=\"https://archive.org/download/SlowMotionFlame/slomoflame_512kb.mp4\"></video></figure>\n<!-- /wp:video -->\n\n<!-- wp:heading -->\n<h2>Custom HTML Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:html -->\n<strong>This is a HTML block.</strong>\n<!-- /wp:html -->\n\n<!-- wp:heading {\"className\":\"has-top-margin\"} -->\n<h2 class=\"has-top-margin\">Preformatted Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:preformatted -->\n<pre class=\"wp-block-preformatted\">This is some preformatted text. Preformatted text keeps your s p a c e s, tabs and<br>linebreaks as they are.</pre>\n<!-- /wp:preformatted -->",
"excerpt": "Audio Block Video Block Custom HTML Block This is a HTML block. Preformatted Block This is some preformatted text. Preformatted text keeps your s p a c e s, tabs andlinebreaks as they are.",
"featuredImage": null,
"tags": [],
"title": "GraphQL or REST? Why not both?"
},
"createPost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1209,
"slug": "graphql-or-rest-why-not-both",
"date": "2023-07-07T03:24:31+00:00",
"status": "draft",
"author": {
"id": 2
},
"categories": [
{
"id": 1
}
],
"rawContent": "<!-- wp:heading -->\n<h2>Audio Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:audio -->\n<figure class=\"wp-block-audio\"><audio controls src=\"https://freemusicarchive.org/file/music/WFMU/Broke_For_Free/Directionless_EP/Broke_For_Free_-_01_-_Night_Owl.mp3\"></audio></figure>\n<!-- /wp:audio -->\n\n<!-- wp:heading -->\n<h2>Video Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:video -->\n<figure class=\"wp-block-video\"><video controls src=\"https://archive.org/download/SlowMotionFlame/slomoflame_512kb.mp4\"></video></figure>\n<!-- /wp:video -->\n\n<!-- wp:heading -->\n<h2>Custom HTML Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:html -->\n<strong>This is a HTML block.</strong>\n<!-- /wp:html -->\n\n<!-- wp:heading {\"className\":\"has-top-margin\"} -->\n<h2 class=\"has-top-margin\">Preformatted Block</h2>\n<!-- /wp:heading -->\n\n<!-- wp:preformatted -->\n<pre class=\"wp-block-preformatted\">This is some preformatted text. Preformatted text keeps your s p a c e s, tabs and<br>linebreaks as they are.</pre>\n<!-- /wp:preformatted -->",
"excerpt": "Audio Block Video Block Custom HTML Block This is a HTML block. Preformatted Block This is some preformatted text. Preformatted text keeps your s p a c e s, tabs andlinebreaks as they are.",
"featuredImage": null,
"tags": [],
"title": "GraphQL or REST? Why not both?"
}
}
}
}ปัญหาของแนวทางที่สอง
วิธีแก้ปัญหาข้างต้นใช้ได้เฉพาะกับการส่งออก ID เท่านั้น (เนื่องจากค่าเหล่านี้คือค่าที่จัดเก็บในฟิลด์การเชื่อมต่อ) มันจะไม่ทำงานกับสิ่งอื่น เช่น slug ของแท็ก:
{
post {
tags {
slug @export(as: "tagSlugs", type: LIST)
}
}
}แนวทางต่อไปนี้จะจัดการกับปัญหานี้
การทำสำเนาโพสต์: แนวทางที่สาม
เราสามารถรันออเปอเรชันเพิ่มเติมในตอนต้นเพื่อกำหนดค่าเริ่มต้นให้กับตัวแปรไดนามิกแต่ละตัวด้วยค่า null หรือค่าว่าง (ผ่านฟิลด์ส่วนกลาง _echo จากส่วนขยาย PHP Functions Via Schema)
จากนั้น ตัวแปรไดนามิกแต่ละตัวจะถูกส่งออกอย่างน้อยหนึ่งครั้งเสมอ เมื่อค่าฟิลด์ไม่ว่างเปล่า มันจะถูกส่งออกอีกครั้ง และค่าที่สองนี้จะเขียนทับค่าแรก
ใน query นี้ ตัวแปรไดนามิก $tagSlugs ถูกกำหนดค่าเริ่มต้นด้วยอาร์เรย์ว่าง และจะถูกส่งออกอีกครั้งหากโพสต์มี slug:
query InitializeDynamicVariables {
tagSlugs: _echo(value: []) @export(as: "tagSlugs")
}
query ExportData
@depends(on: "InitializeDynamicVariables")
{
post {
tags {
slug @export(as: "tagSlugs", type: LIST)
}
}
}- ฟิลด์ส่วนกลาง
_echoคืนค่าทุกสิ่งที่ส่งเข้ามา ไม่ว่าจะเป็นชนิดใดก็ตาม:
query {
string: _echo(value: "page")
int: _echo(value: 3)
bool: _echo(value: true)
jsonObject: _echo(value: {
name: "Robert"
surname: "Spencer"
})
null: _echo(value: null)
arrayOfString: _echo(value: ["something", "new"])
arrayOfInt: _echo(value: [1, 3, 5])
arrayOfArraysOfBool: _echo(value: [[true, false], [false]])
arrayOfMixed: _echo(value: [1, true, "string", [1, 3, 5], {key: "value"}])
}วิธีแก้ปัญหานี้ครอบคลุมกว่าวิธีก่อนหน้า เนื่องจากใช้ได้กับการส่งออกข้อมูลทุกชนิด (ไม่ว่าจะเป็น ID หรืออื่น ๆ)
เมื่อปรับ GraphQL query แล้ว จะกลายเป็นดังนี้:
query InitializeDynamicVariables {
authorID: _echo(value: null) @export(as: "authorID")
categoryIDs: _echo(value: []) @export(as: "categoryIDs")
featuredImageID: _echo(value: null) @export(as: "featuredImageID")
tagIDs: _echo(value: []) @export(as: "tagIDs")}
query GetPostAndExportData($postId: ID!)
@depends(on: "InitializeDynamicVariables")
{
post(by: { id : $postId }) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id @export(as: "authorID")
}
categories {
id @export(as: "categoryIDs", type: LIST)
}
rawContent @export(as: "rawContent")
rawExcerpt @export(as: "excerpt")
featuredImage {
id @export(as: "featuredImageID")
}
tags {
id @export(as: "tagIDs", type: LIST)
}
rawTitle @export(as: "title")
}
}
mutation DuplicatePost
@depends(on: "GetPostAndExportData")
{
createPost(input: {
status: draft,
authorBy: {
id: $authorID
},
categoriesBy: {
ids: $categoryIDs
},
contentAs: {
html: $rawContent
},
excerpt: $excerpt
featuredImageBy: {
id: $featuredImageID
},
tagsBy: {
ids: $tagIDs
},
title: $title
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
post {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}
}คำเตือนในแนวทางที่สาม
เมื่อใดก็ตามที่ตัวแปรไดนามิกถูกส่งออกมากกว่าหนึ่งครั้ง โดยค่าเริ่มต้นเอนจิน GraphQL จะเพิ่มคำเตือนเข้าไปในเรสปอนส์ GraphQL:
{
"extensions": {
"warnings": [
{
"message": "Dynamic variable with name 'tagSlugs' had already been set, had its value overridden",
"locations": [
{
"line": 22,
"column": 21
}
]
}
]
},
"data": {
// ...
}
}แนวทางแบบรวมถัดไปจะจัดการกับคำเตือนนี้
การทำสำเนาโพสต์: แนวทางแบบรวม
เราใช้ GraphQL query จากแนวทางก่อนหน้า และปรับให้เหมาะสมที่สุดโดย:
- ไม่ก่อให้เกิดคำเตือน "ตัวแปรไดนามิกซ้ำ"
- ไม่แสดงค่าของฟิลด์ใน
InitializeDynamicVariablesในเรสปอนส์ GraphQL (เนื่องจากไม่จำเป็น เพราะเป็นเพียงฟิลด์ช่วยเหลือ)
เราจัดการกับองค์ประกอบเหล่านี้โดย (ตามลำดับ):
- เพิ่มไดเรกทีฟ
@configureWarningsOnExportingDuplicateVariable(enabled: false)ให้กับออเปอเรชัน ซึ่งปิดการเกิดคำเตือน - เพิ่มไดเรกทีฟ
@remove(จากส่วนขยาย Field Response Removal) ให้กับแต่ละฟิลด์ที่ต้องการลบ
นี่คือ GraphQL query แบบรวมสำหรับทำสำเนาโพสต์:
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable(enabled: false)
{
authorID: _echo(value: null)
@export(as: "authorID")
@remove
categoryIDs: _echo(value: [])
@export(as: "categoryIDs")
@remove
featuredImageID: _echo(value: null)
@export(as: "featuredImageID")
@remove
tagIDs: _echo(value: [])
@export(as: "tagIDs")
@remove
}
query GetPostAndExportData($postId: ID!)
@depends(on: "InitializeDynamicVariables")
{
post(by: { id : $postId }) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id @export(as: "authorID")
}
categories {
id @export(as: "categoryIDs", type: LIST)
}
rawContent @export(as: "rawContent")
rawExcerpt @export(as: "excerpt")
featuredImage {
id @export(as: "featuredImageID")
}
tags {
id @export(as: "tagIDs", type: LIST)
}
rawTitle @export(as: "title")
}
}
mutation DuplicatePost
@depends(on: "GetPostAndExportData")
{
createPost(input: {
status: draft,
authorBy: {
id: $authorID
},
categoriesBy: {
ids: $categoryIDs
},
contentAs: {
html: $rawContent
},
excerpt: $excerpt
featuredImageBy: {
id: $featuredImageID
},
tagsBy: {
ids: $tagIDs
},
title: $title
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
post {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}
}