Samouczek schematu
Samouczek schematuLekcja 18: Interakcja z zewnętrznymi usługami przez webhooks

Lekcja 18: Interakcja z zewnętrznymi usługami przez webhooks

Webhook to funkcja zwrotna (callback) oparta na HTTP, którą zewnętrzna usługa wywołuje w celu powiadomienia o pewnym zdarzeniu, przekazując wraz z nim ładunek danych. Webhooks umożliwiają komunikację między różnymi aplikacjami internetowymi i usługami.

Kilka przykładów usług wywołujących webhooks:

  • GitHub, gdy do repozytorium zostanie wypchnięty commit
  • Dropbox, gdy dokument zostanie zaktualizowany
  • WooCommerce, gdy zostanie dodane zamówienie
  • Microsoft Teams, do odbierania sformatowanych wiadomości tekstowych i publikowania w publicznych kanałach
  • ConvertKit, gdy subskrybent zostanie aktywowany

Za pomocą Gato GraphQL możemy tworzyć Persisted Queries działające jako webhooks:

  • Ponieważ Persisted Query jest dostępna pod własnym URL-em, może być używana jako cel webhooka
  • Każda Persisted Query może obsługiwać wyłącznie określony webhook

W tej lekcji samouczka utworzymy Persisted Query do interakcji z ConvertKit.

Przeglądanie dokumentacji webhooka

Pierwszym krokiem jest zapoznanie się z dokumentacją serwisu i zrozumienie, jakie dane są przesyłane w ładunku (payload).

Analizując webhooks w ConvertKit, zdarzenia związane z subskrybentami wysyłają żądanie POST na nasz URL z ładunkiem JSON takim jak ten:

{
  "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"
    }
  }
}

Wyodrębnianie danych z ładunku

Ponieważ żądanie jest wysyłane przez POST, musimy wyodrębnić dane z treści żądania HTTP (co jest obsługiwane przez rozszerzenie HTTP Request via Schema).

Jeśli żądanie HTTP jest wykonywane przez GET, Persisted Query może bezpośrednio pobierać elementy danych z parametrów URL.

To zapytanie GraphQL pobiera treść żądania i konwertuje ją na obiekt JSON. Następnie wyodrębnia elementy "subscriber.first_name" i "subscriber.email_address" z obiektu JSON i eksportuje je jako zmienne dynamiczne:

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")
}

Rozszerzenie HTTP Request via Schema pozwala nam pobierać wszystkie dane bieżącego żądania HTTP za pomocą następujących pól:

  • _httpRequestBody: Treść żądania HTTP
  • _httpRequestClientHost: Host klienta
  • _httpRequestClientIP: Adres IP klienta (lub null, jeśli serwer nie jest poprawnie skonfigurowany)
  • _httpRequestCookie: Wartość cookie żądania
  • _httpRequestCookies: Cookies żądania
  • _httpRequestDomain: Domena żądanego URL
  • _httpRequestFullURL: Żądany URL (wraz z parametrami zapytania)
  • _httpRequestHasCookie: Czy żądanie zawiera określone cookie?
  • _httpRequestHasHeader: Czy żądanie zawiera określony nagłówek?
  • _httpRequestHasParam: Czy żądanie zawiera określony parametr?
  • _httpRequestHeader: Wartość nagłówka żądania
  • _httpRequestHeaders: Nagłówki żądania
  • _httpRequestHost: Host żądanego URL
  • _httpRequestMethod: Metoda żądania
  • _httpRequestStringParam: Wartość parametru (przekazanego przez POST lub GET) typu ?param=value
  • _httpRequestStringListParam: Wartość parametru (przekazanego przez POST lub GET) typu ?param[]=value1&param[]=value2
  • _httpRequestParams: Parametry przekazane przez POST lub przez zapytanie URL
  • _httpRequestProtocol: Protokół żądania
  • _httpRequestQuery: Ciąg parametrów zapytania
  • _httpRequestReferer: Referer żądania
  • _httpRequestRequestTime: Znacznik czasu początku żądania
  • _httpRequestScheme: Schemat żądanego URL
  • _httpRequestServerIP: Adres IP serwera
  • _httpRequestURL: Żądany URL (bez parametrów zapytania)
  • _httpRequestURLPath: Ścieżka bezwzględna (zaczynająca się od "/") żądanego URL
  • _httpRequestUserAgent: User agent

Wykonywanie akcji na danych

Po wyodrębnieniu danych z ładunku możemy wykonać na nich pewną akcję.

To zapytanie GraphQL obsługuje zdarzenie subscriber.subscriber_unsubscribe, aby wysłać e-mail do osoby, która anulowała subskrypcję, prosząc o opinię.

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
  }
}