บล็อก

👨🏻‍💻 GraphQL ในฐานะ (คล้ายกับ) ภาษาโปรแกรม

Leonardo Losoviz
โดย Leonardo Losoviz ·

GraphQL แม้จะมี ภาษา GraphQL แต่ก็ไม่ได้ถูกเรียกว่าเป็นภาษาโปรแกรมโดยทั่วไป เพราะมีสิ่งต่างๆ มากมายที่เราทำได้ด้วยภาษาโปรแกรม แต่ไม่สามารถทำได้ด้วย GraphQL

GraphQL มักถูกใช้เพื่อดึงข้อมูล เช่น การเรนเดอร์เว็บไซต์บนฝั่งไคลเอนต์ และเพื่อแก้ไขข้อมูล เช่น การสร้างโพสต์ แค่นั้นเป็นส่วนใหญ่

(การใช้งานอื่นๆ เป็นเพียงการรวมกันของ 2 กรณีก่อนหน้านี้ ตัวอย่างเช่น API gateway อาจดึง/แก้ไขข้อมูลจากเซิร์ฟเวอร์ภายในที่ไม่ได้เปิดเผยต่อไคลเอนต์)

การเข้าถึงข้อมูลใน GraphQL:

query PrintPostTitle($postID: ID!)
{
  post(by: { id: $postID }) {
    title
  }
}

...มีความเทียบเท่า (คล้ายกัน) ใน PHP ดังนี้:

function printPostTitle(int $postID)
{
  $post = getPost($postID);
  echo $post->title;
}

(ตัวอย่างทั้งหมดด้านล่างจะใช้ PHP เป็นภาษาโปรแกรมในการเปรียบเทียบ)

การแก้ไขข้อมูลใน GraphQL:

query UpdatePost($postID: ID!, $title: String!)
{
  updatePost(
    by: { id: $postID },
    input: { title: $title }
  ) {
    title
  }
}

...มีความเทียบเท่า (คล้ายกัน) ใน PHP ดังนี้:

function updatePost(int $postID, string $title)
{
  $post = getPost($postID);
  $post->update(['title' => $title]);
}

สิ่งนี้เพียงพอเพราะ GraphQL มักถูกเข้าถึงจากไคลเอนต์ (เขียนด้วยภาษาโปรแกรมบางอย่าง เช่น JavaScript, PHP, Java หรืออื่นๆ) ซึ่งจะมีตรรกะในการจัดการกับข้อมูล ดังนั้น GraphQL จึงไม่ได้ใช้โดยลำพัง แต่เป็นตัวช่วยของสิ่งอื่น

แต่หาก GraphQL สามารถใช้โดยลำพังได้ กรณีการใช้งานใหม่ๆ มากมายก็สามารถแก้ไขได้โดยใช้เพียง GraphQL ทำให้สามารถนำ GraphQL ไปใช้ในสภาพแวดล้อมใหม่ๆ และรับผิดชอบงานเพิ่มเติมในสแต็กของแอปพลิเคชัน

แต่เพื่อให้สิ่งนั้นเกิดขึ้น GraphQL จำเป็นต้องรองรับคุณสมบัติหลายอย่างของภาษาโปรแกรม

คุณสมบัติของภาษาโปรแกรมที่ GraphQL รองรับมีจำกัด ตัวอย่างเช่น การใช้ directive @include (หรือ @skip) และการส่งตัวแปรเป็น input สามารถถือได้ว่าเป็น (คล้ายกับ) ตรรกะเงื่อนไข:

query PrintPostProperties($postID: ID!, $addContent: Boolean!)
{
  post(by: { id: $postID }) {
    title
    content @include(if: $addContent)
  }
}

queries นี้มีความเทียบเท่าใน PHP ดังนี้:

function printPostProperties(int $postID, bool $addContent)
{
  $post = getPost($postID);
  echo $post->title;
  if ($addContent) {
    echo $post->content;
  }
}

แค่นั้นเป็นส่วนใหญ่ GraphQL ขาดการเรียกซ้ำ, ตัวแปรแบบไดนามิก (ที่ค่าของมันถูกคำนวณและกำหนดให้กับตัวแปรในขณะรันไทม์ ไม่ใช่เป็น input ใน dictionary), การกำหนดตัวแปร (เช่น การกำหนด output ของฟิลด์ให้กับตัวแปร ซึ่งสามารถนำไปใช้เป็น argument ในฟิลด์อื่นได้) และอื่นๆ

ลองคิดดูว่าคุณจะใช้ GraphQL เพียงอย่างเดียวแก้ปัญหาต่อไปนี้ได้อย่างไร:

  • สร้าง webhook ที่จะถูกเรียกโดยบริการเมื่อผู้ใช้ใหม่ลงทะเบียนกับบริการนั้น ผู้ใช้อาจสมัครรับจดหมายข่าว (ระบุด้วยฟิลด์ marketing_optin ใน payload ของ webhook) ในกรณีนั้น webhook จะต้องลงทะเบียนอีเมลของผู้ใช้ (ในฟิลด์ email ใน payload ของ webhook) ในรายการ Mailchimp

คุณคิดว่าเป็นไปได้ไหม? ง่าย? ยาก? หรือเป็นไปไม่ได้?

ที่ Gato GraphQL เราต้องการแก้ปัญหานี้โดยใช้เพียง GraphQL และปัญหาอื่นๆ อีกมากมาย นั่นเป็นเหตุผลที่เราคิดอย่างหนักเกี่ยวกับวิธีรองรับคุณสมบัติของภาษาโปรแกรม

มาดูกันว่าเราได้รองรับคุณสมบัติของโปรแกรมอะไรบ้างบนเซิร์ฟเวอร์ GraphQL ของเรา ในตอนท้ายของโพสต์นี้ เราจะเห็นว่าเราสามารถแก้ปัญหานั้นได้อย่างไร

ฟังก์ชันการทำงาน (Functionality)

ฟิลด์ใน GraphQL โดยปกติจะนำข้อมูลมา เช่น ชื่อเรื่อง เนื้อหา หรือข้อมูลของโพสต์ แต่เรายังสามารถนำฟิลด์มาใช้เป็น "ฟังก์ชันการทำงาน" ได้

ตัวอย่างเช่น การพิมพ์เวลาใน PHP:

function printTime()
{
  echo time();
}

...สามารถทำได้ด้วยฟิลด์ _time ใน GraphQL:

{
  _time
}

สังเกตว่าฟังก์ชัน time ไม่ได้อยู่ในประเภทใด ดังนั้นฟิลด์ _time ก็เช่นกัน ด้วยเหตุนี้ มันจึงเป็น global field และสามารถเข้าถึงได้จากทุกประเภทในสคีมา GraphQL:

{
  posts {
    _time
  }
}

ตัวอย่างอื่นๆ ของ ฟิลด์ฟังก์ชันการทำงาน ได้แก่:

  • _arrayItem
  • _arrayJoin
  • _date
  • _equals
  • _inArray
  • _intAdd
  • _isEmpty
  • _isNull
  • _makeTime
  • _objectProperty
  • _sprintf
  • _strContains
  • _strRegexReplace
  • _strSubstr

ฟังก์ชัน (Functions)

เราสามารถแบ่งหน่วยตรรกะออกเป็นฟังก์ชัน และให้ฟังก์ชันหนึ่งเรียกอีกฟังก์ชันหนึ่ง:

function printPostProperties(int $postID)
{
  $post = getPost($postID);
  printPostTitle();
  printPostContent();
}
 
function printPostTitle(Post $post)
{
  echo $post->title;
}
 
function printPostContent(Post $post)
{
  echo $post->content;
}

ใน GraphQL เราสามารถแบ่งการดำเนินการ query (หรือ mutation) ในเอกสารออกเป็นหลายๆ การดำเนินการ query และให้การดำเนินการหนึ่ง "ขึ้นอยู่กับ" การดำเนินการอื่นๆ ทำให้ดำเนินการเหล่านั้นก่อน:

query PrintPostTitle($postID: ID!)
{
  postWithTitle: post(by: { id: $postID }) {
    title
  }
}
 
query PrintPostContent($postID: ID!)
{
  postWithContent: post(by: { id: $postID }) {
    content
  }
}
 
query PrintPostProperties
  @depends(on: [
    "PrintPostTitle",
    "PrintPostContent"
  ])
{
  # ...
}

ใน queries นี้ การดำเนินการ GraphQL queries โดยส่ง ?operationName=PrintPostProperties ไปยัง endpoint จะทำให้ดำเนินการ queries PrintPostTitle และ PrintPostContent ก่อน แล้วจึงดำเนินการ PrintPostProperties

สิ่งนี้เป็นไปได้ผ่าน Multiple Query Execution

ตัวแปรแบบไดนามิก (Dynamic Variables)

เราสามารถคำนวณค่าและกำหนดให้กับตัวแปรในขณะรันไทม์ จากนั้น ตามค่านั้น เราสามารถดำเนินการฟังก์ชันบางอย่างตามเงื่อนไขหรือไม่ก็ได้:

function printPostProperties(int $postID)
{
  $post = getPost($postID);
  echo $post->title;
  
  $addContent = isUserLoggedIn();
  if ($addContent) {
    echo $post->content;
  }
}

ใน GraphQL เราสามารถ "ส่งออก" ค่าภายใต้ตัวแปรแบบไดนามิกในการดำเนินการบางอย่าง และอ่านค่านี้ในการดำเนินการอื่น:

query ExportAddContent
{
  addContent: isUserLoggedIn
    @export(as: "addContent")
}
 
query PrintPostProperties($postID: ID!)
  @depends(on: "ExportAddContent")
{
  post(by: { id: $postID }) {
    title
    content @include(if: $addContent)
  }
}

สังเกตว่าตัวแปร $addContent ซึ่งเก็บค่าที่ถูกคำนวณในขณะรันไทม์ ถูกอ่านโดยแต่ไม่ได้ประกาศในการดำเนินการ PrintPostProperties เพราะมันเป็น ตัวแปรแบบไดนามิก

การดำเนินการฟังก์ชันตามเงื่อนไข

อีกทางเลือกหนึ่งจากตัวอย่างก่อนหน้าคือ การจัดกลุ่มตรรกะเป็นฟังก์ชัน แล้วดำเนินการฟังก์ชันตามเงื่อนไขหรือไม่ก็ได้ขึ้นอยู่กับค่าของตัวแปรแบบไดนามิก:

function printPostProperties(int $postID)
{
  $post = getPost($postID);
  printPostTitle();
  
  $addContent = isUserLoggedIn();
  if ($addContent) {
    printPostContent();
  }
}
 
function printPostTitle(Post $post)
{
  echo $post->title;
}
 
function printPostContent(Post $post)
{
  echo $post->content;
}

ใน GraphQL เราสามารถเพิ่ม directive @include ในการดำเนินการ:

query ExportAddContent
{
  addContent: isUserLoggedIn
    @export(as: "addContent")
}
 
query PrintPostTitle($postID: ID!)
{
  postWithTitle: post(by: { id: $postID }) {
    title
  }
}
 
query PrintPostContent($postID: ID!)
  @depends(on: "ExportAddContent")
  @include(if: $addContent)
{
  postWithContent: post(by: { id: $postID }) {
    content
  }
}
 
query PrintPostProperties
  @depends(on: [
    "PrintPostTitle",
    "PrintPostContent"
  ])
{
  # ...
}

ตอนนี้ การดำเนินการ PrintPostContent จะถูกดำเนินการเฉพาะเมื่อ $addContent เป็น true เท่านั้น

การกำหนดตัวแปรและการส่งกลับ

มาปรับตัวอย่างก่อนหน้าเล็กน้อย โดยในตัวอย่างนั้น เงื่อนไข "addContent" ผูกกับว่าผู้ใช้ล็อกอินหรือไม่

ในตัวอย่างอื่นนี้ "addContent" จะเป็น true เมื่อวันนี้เป็นวันหยุดสุดสัปดาห์ ซึ่งต้องใช้ตรรกะบางอย่างในการคำนวณ:

  • ดึงวันที่ของวันนี้
  • จัดรูปแบบเป็นชื่อวัน ในตัวพิมพ์เล็ก
  • ตรวจสอบว่าเป็น "saturday" หรือ "sunday"

ใน PHP:

function addContent()
{
  $today = time();
  $dayName = date('l', $today);
  $lcDayName = strtolower($dayName);
  $isWeekend = in_array(
    $lcDayName,
    ['saturday', 'sunday']
  );
  return $isWeekend;
}
 
function printPostProperties(int $postID)
{
  $post = getPost($postID);
  echo $post->title;
 
  $addContent = addContent();
  if ($addContent) {
    echo $post->content;
  }
}

ใน GraphQL:

query ExportAddContent
{
  today: _time
  dayName: _date(format: "l", timestamp: $__today)
  lcDayName: _strLowerCase(text: $__dayName)
  isWeekend: _inArray(
    value: $__lcDayName
    array: ["saturday", "sunday"],
  )
    @export(as: "addContent")
}
 
query PrintPostProperties($postID: ID!)
  @depends(on: "ExportAddContent")
{
  post(by: { id: $postID }) {
    title
    content @include(if: $addContent)
  }
}

ในการดำเนินการ ExportAddContent ค่าของแต่ละฟิลด์ที่ถูก queries จะพร้อมใช้งานทันทีสำหรับฟิลด์ด้านล่าง ภายใต้ตัวแปรแบบไดนามิก $__fieldName วิธีนี้ทำให้ output ของฟิลด์สามารถนำไปใช้เป็น input ของฟิลด์อื่นได้ทันทีภายในการดำเนินการเดียวกัน

สิ่งนี้เป็นไปได้ด้วย Field to Input

การแก้ไขค่าแบบไดนามิก

ในตัวอย่าง PHP นี้ เราแก้ไขค่าของตัวแปรเมื่อผู้ใช้ที่ล็อกอินเป็นผู้ดูแลระบบ ซึ่งในกรณีนั้น เนื้อหาของโพสต์จะถูกเพิ่มลิงก์เพื่อแก้ไขโพสต์:

function isAdminUser()
{
  $user = getCurrentUser();
  return in_array("administrator", $user->roles);
}
 
function printPostContent(int $postID)
{
  $post = getPost($postID);
  $postContent = $post->content;
 
  $isAdminUser = isAdminUser();
  if ($isAdminUser) {
    $postContent = sprintf(
      '%s<p><a href="%s">%s</a></p>',
      $postContent,
      $post->edit_url,
      '(Admin only) Edit post'
    ) 
  }
 
  echo $postContent;
}

ใน GraphQL เราสามารถดำเนินการอย่างใดอย่างหนึ่งตามเงื่อนไข สร้างค่าที่แตกต่างกันสำหรับฟิลด์บางฟิลด์:

query InitializeDynamicVariables
{
  isAdminUser: _echo(value: false)
    @export(as: "isAdminUser")
}
 
query ExportConditionalVariables
  @depends(on: "InitializeDynamicVariables")
{
  me {
    roleNames
    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
    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
  }
}
 
query ExecuteAll
  @depends(on: [
    "RetrieveContentForAdminUser",
    "RetrieveContentForNonAdminUser"
  ])
{
  # ...
}

การใช้ directives @include และ @skip ด้วยตัวแปรแบบไดนามิกเดียวกันเป็น input ทำให้การดำเนินการ RetrieveContentForAdminUser และ RetrieveContentForNonAdminUser ไม่สามารถเกิดขึ้นพร้อมกันได้

การวนซ้ำ Array

สมมติว่าเราต้องการวนซ้ำรายการใน array และแปลงค่าเหล่านั้นเป็นตัวพิมพ์ใหญ่:

function printUserRolesAsUppercase(int $userID)
{
  $user = getUser($userID);
  foreach ($user->roles as $role) {
    echo strtoupper($role);
  }
}

ใน GraphQL เราสามารถใช้ directive @underEachArrayItem เพื่อวนซ้ำรายการ array และส่งค่าแต่ละค่าไปยัง directive ถัดไปในเชน ในกรณีนี้คือ @strUpperCase:

query PrintUserRolesAsUppercase($userID: ID!)
{
  user(by: { id: $userID }) {
    roles
      @underEachArrayItem
        @strUpperCase
  }
}

สิ่งนี้เป็นไปได้ด้วย composable directives

การดำเนินการ CRUD จำนวนมาก

CRUD ย่อมาจาก Create (สร้าง), Read (อ่าน), Update (อัปเดต) และ Delete (ลบ) ซึ่งเป็นการดำเนินการที่เราทำกับทรัพยากร (โพสต์, ผู้ใช้ ฯลฯ)

การอ่านจำนวนมากใน PHP มีลักษณะดังนี้:

function getPostTitles()
{
  $posts = getPosts();
  foreach ($posts as $post) {
    echo $post->title;
  }
}

กรณีการใช้งานนี้ได้รับการตอบสนองโดยธรรมชาติด้วย GraphQL:

query GetPostTitles
{
  posts {
    title
  }
}

การอัปเดตจำนวนมากใน PHP มีลักษณะดังนี้:

function updatePostTitlesAsUppercase()
{
  $posts = getPosts();
  foreach ($posts as $post) {
    $post->update(['title' => strtoupper($post->title)]);
  }
}

การดำเนินการอัปเดตจำนวนมากใน GraphQL มักรองรับโดยการสร้าง mutation เฉพาะ updatePosts ที่รับข้อมูลสำหรับโพสต์ทั้งหมด

ฉันไม่ชอบแนวทางนี้ เพราะมันเพิ่มจำนวน mutation ในสคีมาเป็นสองเท่า (อันหนึ่งสำหรับแก้ไขทรัพยากรเดียว อีกอันสำหรับแก้ไขทรัพยากรหลายรายการ) และเราต้องดูแลรักษาตรรกะสำหรับทั้งสองอัน:

  • updatePost + updatePosts
  • createPost + createPosts
  • ฯลฯ

ในความเห็นของฉัน แนวทางที่สวยงามกว่าคือการใช้ nested mutations ซึ่ง mutation Post.update จะถูกใช้กับแต่ละทรัพยากรที่ถูก queries:

mutation UpdatePostTitlesAsUppercase
{
  posts {
    title
    ucTitle: _strUpperCase(text: $__title)
    update(
      input: { title: $__ucTitle }
    ) {
      status
      post {
        title
      }
    }
  }
}

แนวทางเดียวกันใช้ได้กับการลบทรัพยากร:

function deletePosts()
{
  $posts = getPosts();
  foreach ($posts as $post) {
    $post->delete();
  }
}

ใน GraphQL:

mutation DeletePosts
{
  posts {
    delete {
      status
    }
  }
}

สำหรับการสร้าง เราไม่ส่งทรัพยากรเพราะยังไม่มี แต่เราให้ array ที่มี data input สำหรับทรัพยากรทั้งหมดที่จะสร้าง:

function createPosts()
{
  $postDataItems = [
    [
      'title' => 'First title',
      'content' => 'First content',
    ],
    [
      'title' => 'Second title',
      'content' => 'Second content',
    ],
  ];
  foreach ($postDataItems as $postDataItem) {
    $post = new Post($postDataItem['title'], $postDataItem['content']);
    $post->save();
  }
}

การสร้างโพสต์จำนวนมากใน GraphQL โดยใช้ mutation createPost เดียวนั้นซับซ้อนเล็กน้อย แต่ก็ยังทำได้

แนวคิดคือการวนซ้ำ array ที่มี data input กำหนดแต่ละรายการภายใต้ตัวแปรแบบไดนามิก $input แล้วดำเนินการ mutation createPost โดยส่ง input นั้น สุดท้าย เราได้รับ ID ที่ได้จากโพสต์ที่สร้างแล้วภายใต้ตัวแปรแบบไดนามิก $createdPostIDs และดึงข้อมูลของมัน:

mutation CreatePosts
  @depends(on: "GetPostsAndExportData")
{
  createdPostIDs: _echo(value: [
    {
      title: "First title",
      content: "First content"
    },
    {
      title: "Second title",
      content: "Second content"
    },
  ])
    @underEachArrayItem(
      passValueOnwardsAs: "input"
    )
      @applyField(
        name: "createPost"
        arguments: {
          input: $input
        },
        setResultInResponse: true
      )
    @export(as: "createdPostIDs")
}
 
query RetrieveCreatedPosts
  @depends(on: "CreatePosts")
{
  createdPosts: posts(
    filter: {
      ids: $createdPostIDs,
    }
  ) {
    title
    content
  }
}

การส่ง HTTP Request (และฟังก์ชันอื่นๆ)

การส่ง HTTP request ไปยัง webserver บางแห่งสามารถทำได้ผ่านฟังก์ชันเฉพาะใน PHP เช่น file_get_contents หรือ curl_exec

การใช้ file_get_contents:

$xml = file_get_contents("http://www.example.com/file.xml");

ใน GraphQL ตรรกะสำหรับดำเนินการ HTTP request สามารถทำได้ผ่านฟิลด์ฟังก์ชันการทำงาน เช่น _sendHTTPRequest:

query {
  _sendHTTPRequest(input: {
    url: "http://www.example.com/file.xml",
    method: GET
  }) {
    xml: body
  }
}

แนวคิดเดียวกันใช้ได้กับฟังก์ชันการทำงานใดๆ

ตัวอย่างเช่น เราเข้าถึงค่าของ constant ใน PHP ดังนี้:

$mailchimpUsername = constant('MAILCHIMP_API_CREDENTIALS_USERNAME');

เราสามารถนำ ฟิลด์ฟังก์ชันการทำงานที่เกี่ยวข้องมาใช้ใน GraphQL:

{
  mailchimpUsername: _env(name: "MAILCHIMP_API_CREDENTIALS_USERNAME")
}

การแก้ปัญหาโดยใช้เพียง GraphQL

ด้วยคุณสมบัติทั้งหมดของภาษาโปรแกรมที่เราเพิ่งกล่าวถึง เราสามารถใช้เพียง GraphQL เพื่อแก้ปัญหาที่ตั้งไว้ก่อนหน้า:

  • สร้าง webhook ที่จะถูกเรียกโดยบริการเมื่อผู้ใช้ใหม่ลงทะเบียนกับบริการนั้น ผู้ใช้อาจสมัครรับจดหมายข่าว (ระบุด้วยฟิลด์ marketing_optin ใน payload ของ webhook) ในกรณีนั้น webhook จะต้องลงทะเบียนอีเมลของผู้ใช้ (ในฟิลด์ email ใน payload ของ webhook) ในรายการ Mailchimp

วิธีแก้ปัญหาคือการใช้ GraphQL persisted query เป็น webhook ด้วย queries นี้:

query HasSubscribedToNewsletter {
  hasSubscriberOptIn: _httpRequestHasParam(name: "marketing_optin")
  subscriberOptIn: _httpRequestStringParam(name: "marketing_optin")
  isNotSubscriberOptInNAValue: _notEquals(value1: $__subscriberOptIn, value2: "NA")
  subscribedToNewsletter: _and(values: [$__hasSubscriberOptIn, $__isNotSubscriberOptInNAValue])
    @export(as: "subscribedToNewsletter")
}
 
query MaybeCreateContactOnMailchimp
   @depends(on: "HasSubscribedToNewsletter")
   @include(if: $subscribedToNewsletter)
{
  subscriberEmail: _httpRequestStringParam(name: "email")
  
  mailchimpUsername: _env(name: "MAILCHIMP_API_CREDENTIALS_USERNAME")
   
  mailchimpPassword: _env(name: "MAILCHIMP_API_CREDENTIALS_PASSWORD")
   
  
  mailchimpListMembersJSONObject: _sendJSONObjectItemHTTPRequest(input: {
    url: "https://us7.api.mailchimp.com/3.0/lists/{listCode}/members",
    method: POST,
    options: {
      auth: {
        username: $__mailchimpUsername,
        password: $__mailchimpPassword
      },
      json: {
        email_address: $__subscriberEmail,
        status: "subscribed"
      }
    }
  })
}

ในวิธีแก้ปัญหานี้ การดำเนินการ MaybeCreateContactOnMailchimp ซึ่งดำเนินการ HTTP request กับ API ของ Mailchimp จะถูกดำเนินการตามเงื่อนไข ขึ้นอยู่กับค่าของฟิลด์ marketing_optin

(อ่านบล็อกโพสต์ 👨🏻‍🏫 GraphQL query to automatically send the newsletter subscribers from InstaWP to Mailchimp เพื่อดูวิธีการทำงานของ queries นี้)

GraphQL ทรงพลังกว่าที่คุณคิด!

GraphQL สามารถใช้ได้มากกว่าแค่การดึงและแก้ไขข้อมูล... ปรับแต่งข้อมูล, แก้ไข output แบบไดนามิก, กำหนดเนื้อหาสำหรับบริบทที่แตกต่างกัน, สร้าง API gateway ด้วยโค้ดไม่กี่บรรทัด และอื่นๆ อีกมากมาย

ด้วยการรองรับคุณสมบัติของภาษาโปรแกรม เราสามารถแก้ปัญหาข้างต้นโดยใช้เพียง GraphQL และหลีกเลี่ยงการใช้งานไคลเอนต์ที่ต้องติดตั้งคู่กัน จึงทำให้สแต็กแอปพลิเคชันง่ายขึ้น: ส่วนที่เคลื่อนไหวน้อยลง, ความซับซ้อนน้อยลง, โค้ดที่ต้องดีบักน้อยลง, เทคโนโลยีที่ต้องจัดการน้อยลง

GraphQL ยอดเยี่ยมมาก 🤘


สมัครรับจดหมายข่าวของเรา

ติดตามการอัปเดตทั้งหมดของ Gato GraphQL