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 (lubnull, 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¶m[]=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
}
}