บทช่วยสอน Schema
บทช่วยสอน Schemaบทเรียนที่ 25: การแปลงข้อมูลจาก API ภายนอก

บทเรียนที่ 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:) ด้วย) ตรรกะจะถูกดำเนินการหรือไม่ขึ้นอยู่กับเงื่อนไขจากเอนทิตีนั้น

ด้วยวิธีนี้ เราสามารถแก้ไขการตอบกลับสำหรับบางเอนทิตี (และไม่ใช่เอนทิตีอื่น) แบบไดนามิก โดยอิงตามเงื่อนไขต่าง ๆ เช่น:

  • โพสต์มีคอมเมนต์หรือไม่?
  • คอมเมนต์มีการตอบกลับหรือไม่?
  • ผู้ใช้เป็นผู้ดูแลระบบหรือไม่?
  • แท็ก/หมวดหมู่ถูกนำไปใช้กับโพสต์ใดหรือไม่?
  • ฯลฯ