บทช่วยสอน Schema
บทช่วยสอน Schemaบทเรียนที่ 18: การโต้ตอบกับบริการภายนอกผ่าน Webhook

บทเรียนที่ 18: การโต้ตอบกับบริการภายนอกผ่าน Webhook

Webhook คือฟังก์ชัน callback ที่ทำงานบน HTTP ซึ่งบริการภายนอกจะเรียกใช้เพื่อแจ้งเตือนเหตุการณ์บางอย่าง พร้อมส่งเพย์โหลดของข้อมูลไปด้วย Webhook ช่วยให้เว็บแอปและบริการต่าง ๆ สื่อสารกันได้

ตัวอย่างของบริการที่เรียกใช้ Webhook ได้แก่:

  • GitHub เมื่อมีการ push commit ไปยัง repository
  • Dropbox เมื่อเอกสารถูกอัปเดต
  • WooCommerce เมื่อมีการเพิ่มคำสั่งซื้อ
  • Microsoft Teams เพื่อรับข้อความ rich text และโพสต์ในช่องสาธารณะ
  • ConvertKit เมื่อสมาชิกถูกเปิดใช้งาน

ด้วย Gato GraphQL เราสามารถสร้าง Persisted Queries ที่ทำหน้าที่เป็น Webhook ได้:

  • เนื่องจาก Persisted Query ถูกเปิดเผยภายใต้ URL ของตัวเอง จึงสามารถใช้เป็นเป้าหมายของ Webhook ได้
  • Persisted Query แต่ละรายการสามารถจัดการ Webhook เฉพาะรายการได้โดยเฉพาะ

ในบทเรียนนี้ เราจะสร้าง Persisted Query เพื่อโต้ตอบกับ ConvertKit

การเรียกดูเอกสารของ Webhook

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

เมื่อวิเคราะห์ webhooks ใน ConvertKit เหตุการณ์ที่เกี่ยวข้องกับสมาชิกจะส่งคำขอ POST มายัง URL ของเราพร้อมเพย์โหลด JSON แบบนี้:

{
  "subscriber": {
    "id": 1,
    "first_name": "John",
    "email_address": "John@example.com",
    "state": "active",
    "created_at": "2018-02-15T19:40:24.913Z",
    "fields": {
      "My Custom Field": "Value"
    }
  }
}

การดึงข้อมูลออกจากเพย์โหลด

เนื่องจากคำขอถูกส่งมาผ่าน POST เราจึงต้องดึงข้อมูลออกจากเนื้อหา (body) ของคำขอ HTTP (ซึ่งรองรับผ่านส่วนขยาย HTTP Request via Schema)

หากคำขอ HTTP ถูกดำเนินการผ่าน GET Persisted Query จะสามารถดึงรายการข้อมูลจากพารามิเตอร์ของ URLได้โดยตรง

GraphQL query นี้จะดึงเนื้อหาของคำขอและแปลงเป็นออบเจ็กต์ JSON จากนั้นจะดึงรายการ "subscriber.first_name" และ "subscriber.email_address" ออกจากออบเจ็กต์ JSON และส่งออกเป็นตัวแปรแบบไดนามิก:

query ExtractPayloadData {
  body: _httpRequestBody
  bodyJSONObject: _strDecodeJSONObject(string: $__body)
 
  subscriberFirstName: _objectProperty(
    object: $__bodyJSONObject,
    by: { path: "subscriber.first_name" }
  )
    @export(as: "subscriberFirstName")
  
  subscriberEmail: _objectProperty(
    object: $__bodyJSONObject,
    by: { path: "subscriber.email_address" }
  )
    @export(as: "subscriberEmail")
}

ส่วนขยาย HTTP Request via Schema ช่วยให้เราดึงข้อมูลทั้งหมดของคำขอ HTTP ปัจจุบันได้ ผ่านฟิลด์ต่อไปนี้:

  • _httpRequestBody: เนื้อหาของคำขอ HTTP
  • _httpRequestClientHost: โฮสต์ของไคลเอนต์
  • _httpRequestClientIP: ที่อยู่ IP ของไคลเอนต์ (หรือ null หากเซิร์ฟเวอร์ตั้งค่าไม่ถูกต้อง)
  • _httpRequestCookie: ค่า Cookie ของคำขอ
  • _httpRequestCookies: Cookie ของคำขอ
  • _httpRequestDomain: โดเมนของ URL ที่ร้องขอ
  • _httpRequestFullURL: URL ที่ร้องขอ (รวมพารามิเตอร์ query)
  • _httpRequestHasCookie: คำขอมี Cookie ที่ระบุหรือไม่?
  • _httpRequestHasHeader: คำขอมี header ที่ระบุหรือไม่?
  • _httpRequestHasParam: คำขอมีพารามิเตอร์ที่ระบุหรือไม่?
  • _httpRequestHeader: ค่า header ของคำขอ
  • _httpRequestHeaders: header ของคำขอ
  • _httpRequestHost: โฮสต์ของ URL ที่ร้องขอ
  • _httpRequestMethod: เมธอดของคำขอ
  • _httpRequestStringParam: ค่าของพารามิเตอร์ (ส่งผ่าน POST หรือ GET) ในรูปแบบ ?param=value
  • _httpRequestStringListParam: ค่าของพารามิเตอร์ (ส่งผ่าน POST หรือ GET) ในรูปแบบ ?param[]=value1&param[]=value2
  • _httpRequestParams: พารามิเตอร์ที่ส่งผ่าน POST หรือผ่าน query ของ URL
  • _httpRequestProtocol: โปรโตคอลของคำขอ
  • _httpRequestQuery: สตริงของพารามิเตอร์ query
  • _httpRequestReferer: referer ของคำขอ
  • _httpRequestRequestTime: timestamp ของจุดเริ่มต้นของคำขอ
  • _httpRequestScheme: scheme ของ URL ที่ร้องขอ
  • _httpRequestServerIP: ที่อยู่ IP ของเซิร์ฟเวอร์
  • _httpRequestURL: URL ที่ร้องขอ (ไม่รวมพารามิเตอร์ query)
  • _httpRequestURLPath: พาธสัมบูรณ์ (ขึ้นต้นด้วย "/") ของ URL ที่ร้องขอ
  • _httpRequestUserAgent: User agent

การดำเนินการบางอย่างกับข้อมูล

เมื่อเราดึงข้อมูลออกจากเพย์โหลดแล้ว เราก็สามารถดำเนินการบางอย่างกับข้อมูลนั้นได้

GraphQL query นี้จัดการกับเหตุการณ์ subscriber.subscriber_unsubscribe เพื่อส่งอีเมลไปยังผู้ที่ยกเลิกการสมัคร เพื่อขอความคิดเห็น

query CreateEmailMessage
  @depends(on: "ExtractPayloadData")
{
  emailMessageTemplate: _strConvertMarkdownToHTML(
    text: """
 
Hey {$subscriberFirstName}, it's sad to let you go!
 
Please be welcome to complete [this form](https://forms.gle/FpXNromWAsZYC1zB8) and let us know if there is anything we can do better.
 
Thanks. Hope to see you back!
 
    """
  )
  emailMessage: _strReplaceMultiple(
    search: ["{$subscriberFirstName}"],
    replaceWith: [$subscriberFirstName],
    in: $__emailMessageTemplate
  )
    @export(as: "emailMessage")
}
 
mutation SendEmail @depends(on: "CreateEmailMessage") {
  _sendEmail(
    input: {
      to: $subscriberEmail
      subject: "Would you like to give us feedback on how we can improve?"
      messageAs: {
        html: $emailMessage
      }
    }
  ) {
    status
  }
}