• CloudPouch NEW!
  • Akademia
  • Blog
  • O stronie
  • Home

Amazon EventBridge API Destinations - integracja z RESTowymi endpointami bez funkcji Lambda


Amazon EventBridge API Destinations
Uwielbiam ❤️ pracę z usługą Amazon EventBridge. Nie jest to dużym zaskoczeniem, gdyż jest ona uwielbiana przez społeczność. Jednak dla mnie to nie tylko czysta techniczna doskonałość tego rozwiązania o tym decyduje.

Ilekroć myślę o EventBridge słyszę w głowie słynne słowa z filmu TRON. Zostały one nawet ponownie użyte na samym początku sequela TRON: Legacy.

I tried to picture clusters of information as they moved through the computer.
What do they look like? Ships? Motorcycles?
Were the circuits like freeways?
I kept dreaming of a world I thought I’d never see.
And then, one day…
I got in.

Mimo, że słowa te zostały wypowiedziane o sprzęcie komputerowym, a nie o magistrali komunikacyjnej per se, moim zdaniem doskonale się do niej odnoszą.

Za każdym razem, gdy pracuję z EventBridge towarzyszy mi uczucie ekscytacji science-fiction, które pochodzi z tego filmu.

Mam nadzieję, że Tobie też udzieli się ten vibe po przeczytaniu artykułu!

Czego nauczysz się z artykułu

Ten tutorial nie jest tylko o integracji z Mailchimpem. Powinieneś go przeczytać, jeśli chcesz dowiedzieć się, jak:

  • skonfigurować Amazon EventBridge API Destinations, aby wysyłać żądania REST do dowolnego endpointu 3rd party w internecie.
  • używać parametrów ścieżki HTTP do uruchamiania różnych endpointów na podstawie treści wiadomości. Jest to bardzo ważne, ponieważ prawie zupełnie tego nie wyjaśniono w dokumentacji i nie ma żadnych przykładów w internecie opisujących tę funkcjonalność - o ile mi wiadomo jestem pierwszy 😉
  • skonfigurować i wdrożyć przykładowy projekt wykorzystujący Serverless Framework, aby łatwo potestować na włąsną rękę na swoim koncie AWS
  • zintegrować go z Mailchimpem, aby tagować użytkowników na podstawie wiadomości na szynie zdarzeń (EventBus).
  • i wreszcie, co zrobić, gdy coś nie działa (jak debugować integracje API Destinations)?

Tło biznesowe

Ten tutorial jest oparty na moich doświadczeniach podczas wdrażania integracji API Destinations z Mailchimpem.

Mam małą platformę e-commerce Akademia Serverless Polska, która sprzedaje kursy online. Za każdym razem, gdy klient kupi któryś z produktów, chcę zaznaczyć tę informację w moim systemie do maili (Email Service Provider - ESP). Moim ESP jest Mailchimp i chcę nadać klientowi konkretny tag związany z produktem, aby w przyszłości nie wysyłać mu promocyjnych e-maili o produktach, które już posiada. Niestety, moja platforma e-commerce nie jest w stanie tagować użytkowników w Mailchimp, więc musiałem to zaimplementować samodzielnie.

Oczywiście wykorzystałem serverless i jak zawsze była to świetna zabawa i dużo nauki 😃

Architektura wysokopoziomowa

Spójrz na poniższy diagram

Architektura wysokopoziomowa

Pobieranie zamówień z platformy e-commerce jest poza zakresem tego artykułu. Skupimy się na EventBridge i integracji z Mailichimp za pomocą API Destinations. Zakładam, że wiesz jak wysłać nowe zdarzenie do custom Event Bus. A jak nie to się dowiesz 😉

Co to jest API Destinations?

API Destinations to stosunkowo nowa funkcjonalność Amazon EventBridge, która pozwala nam na integrację z endpointami REST firm trzecich w Internecie bezpośrednio bez użycia funkcji Lambda!

Wszystko co musisz zrobić, to skonfigurować usługę zamiast pisać własny kod. Jak zobaczysz, trzeba napisać sporo CloudFormation. Jednak w porównaniu z własną implementacją uzyskasz znacznie lepszy efekt.

Ta aktualizacja jest zgodna z pryncypium AWS wygłoszonym przez Chrissa Munnsa podczas re:Invent 2019 używaj funkcji do przekształcania, a nie transportu danych (use functions to transform, not transport).
Chriss Munns podczas re:Invent 2019
I to wyjaśnia całą ideę, która za tym stoi. Zostawmy przyziemne zadanie wywoływania 3rd party endpointu AWSowi (transport danych). Wymieniamy kod (własna implementacja funkcji Lambda) na konfigurację usługi. W zamian dostajemy niezawodne rozwiązanie:

  • które zawsze działa
  • ktoś inny bierze za nie odpowiedzialność
  • które jest rozwijane przez najlepszych inżynierów jakich można znaleźć. 😃

Implementacja

W prawdziwym życiu nie ma miejsca na klikanie i ręczne definiowanie infrastruktury. Profesjonalne projekty wymagają automatyzacji, powtarzalności, niezawodności i reużywalności.

Dlatego w tym artykule zamiast zrzutów ekranu z konsoli AWS przedstawię fragmenty kodu będąc zgodnym z praktyką Infrastructure as Code.

Jeśli jesteś niecierpliwy, możesz już teraz sprawdzić ten przykładowy projekt na GitHub, który zawiera wszystkie źródła. W dalszej części artykuł wyjaśniam wszystko po kolei.

Komponenty rozwiązania

Szyna zdarzeń - Event Bus

Aby skonfigurować API Destinations potrzebujemy naszą włąsną szynę zdarzeń (custom Event Bus), która jest szkieletem naszego rozwiązania. Jest ona prosta do zdefiniowania za pomocą CloudFormation.

1
2
3
4
EventBus:
Type: AWS::Events::EventBus
Properties:
Name: ${self:service}-${self:provider.stage}

Obie zmienne ${self:service} oraz ${self:provider.stage} pochodzą z Serverless Framework (SF). Pozwólcie, że wyjaśnię, dla tych z Was, którzy nie są biegli w SF. Pierwsza z nich przechowuje nazwę projektu, a druga nazwę stage’a, do którego usługa jest deployowana. Dzięki temu nie mam konfliktu nazw, nawet wtedy gdy różne stage‘e tego samego projektu są deployowane do tego samego regionu (lub w ogóle, bo niektóre zasoby są globalne np. S3 buckets, IAM Roles). Osobiście używam nazw stage’ów dev, test i prod w moich projektach.

Połączenie - Connection

Następnie potrzebujemy obiekt AWS::Events::Connection, który zawiera dane uwierzytelniające (takie jak nazwa użytkownika i hasło) do endpointu.

1
2
3
4
5
6
7
8
9
MailchimpConnection:
Type: AWS::Events::Connection
Properties:
Name: MailchimpConnection-${self:provider.stage}
AuthorizationType: BASIC
AuthParameters:
BasicAuthParameters:
Username: "randomUser"
Password: ${ssm:mailchimp-api-key~true}

Do logowania do Mailchimp użyjemy autoryzacji typu BASIC. W przypadku parametru Username Mailchimp dopuszcza dowolny ciąg znaków i interesuje go tylko część Password. Z perspektywy Mailchimpa wartość Password jest kluczem Api Key, który można wygenerować w menu Mailchimp wybierając Account-> Extras-> API Keys.

Autoryzacja typu BASIC spowoduje, że do żądania tworzonego przez API Destinations podczas wywoływania endpointu dodany będzie nagłówek authorization. Wygląda to mniej więcej tak:

1
authorization	Basic cmFuZG9tVXNlcjpZlPkmY2hpbXBIcGlQYXNzd5CyZA==

Wartość parametru Password jest ustawiona na ${ssm:mailchimp-api-key~true}, co jest wbudowaną opcją Serverless Framework. Pobiera ona wartość parametru z Systems Manager Parameter Store w chmurze (prefiks ssm) podczas deploymentu. Parametr ma nazwę mailchimp-api-key a ~true oznacza, że musi być odszyfrowany. Więcej na ten temat w dokumentacji Serverless Framework.

Cel (destynacja) - ApiDestination

To co może być dla Ciebie dziwne to fakt, że nie zdefiniowaliśmy adresu URL endpointu w obiekcie połączenia. Robi się to w AWS::Events::ApiDestination.

1
2
3
4
5
6
7
8
MailchimpApiDestination:
Type: AWS::Events::ApiDestination
Properties:
Name: mailchimp-tag-${self:provider.stage}
ConnectionArn: !GetAtt MailchimpConnection.Arn
InvocationEndpoint: ${self:custom.mailchimp.endpoint}/lists/${self:custom.mailchimp.list}/segments/*/members
HttpMethod: POST
InvocationRateLimitPerSecond: 20

Mamy tu trzy ciekawe elementy:

  • InvocationEndpoint
  • HttpMethod
  • InvocationRateLimitPerSecond

W tej chwili chcę, abyś w pełni zrozumiał jego znaczenie. Adres URL endpointa może być parametryzowany na podstawie payload zdarzenia wysłanego do EventBusa. Jest to świetne, ponieważ pozwala nam na ponowne użycie pojedynczej konfiguracji ApiDestination do wysyłania danych do złożonych endpointów.

Kolejnym znakomitym dodatkiem do API Destinations jest InvocationRateLimitPerSecond. Pozwala nam na ograniczenie częstotliwości zapytań odpalanych przez API Destination do endpointu 3rd party. Oczywiście jest to bardzo istotna rzecz do rozważenia podczas integracji, ponieważ nie wszystkie systemy są tak skalowalne jak rozwiązania serverless na AWS. Tutaj dostajemy to za darmo i bez żadnego dodatkowego kodowania.

Mam nadzieję, że to niesamowicie przydatne ustawienie zostanie dodane do innych konstrukcji w rodzinie EventBridge. Mógłbym sobie wyobrazić dodanie rate limitu do istniejących celów Lambda lub jeszcze nieistniejącego celu Simple Email Service (co drogie AWS byłoby super gdybyście dodali 🤞) 😉

Reguła - Rule

Ostatnim elementem układanki specyficznym dla EventBridge jest obiekt AWS::Events::Rule, który zawiera Target. Obiekt Rule działa jak router lub dyspozytor. Mówi on naszemu custom EventBusowi, które zdarzenia wysłać gdzie. Obiekt Target definiuje część gdzie i wiąże razem Rule z nową funkcjonalnością API Destinations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ApiDestinationDeliveryRule:
Type: AWS::Events::Rule
Properties:
EventBusName: !Ref EventBus
Name: SendOrderEventsToApiDestinations
EventPattern:
detail-type:
- ORDER_COURSE_SERVERLESS
- ORDER_COURSE_DATALAKE
State: "ENABLED"
Targets:
- Id: MailchimpApiDestination
Arn: !GetAtt MailchimpApiDestination.Arn
RoleArn: !GetAtt ApiDestinationsTargetRole.Arn
InputTransformer:
InputPathsMap:
mcTagId: $.detail.mcTagId
email: $.detail.email
InputTemplate: >
{
"email_address": <email>
}
HttpParameters:
PathParameterValues:
- $.detail.mcTagId

W sekcji EventPattern zdefiniowane jest, do jakich zdarzeń odnosi się ta reguła. W moim przypadku jest ona ograniczona tylko do zdarzeń Order.

Teraz porozmawiajmy o targetach. Pojedyncza Rule może definiować ich wiele, tutaj mamy tylko jeden, nazwany MailchimpApiDestination. Target odnosi się do zdefiniowanego powyżej ApiDestination, wymaga on dedykowanej roli IAM Role.

Definiuje on również InputTransformer, który pozwala nam modyfikować payload zdarzeń i dostosowywać je do specyfikacji API docelowego endpointu. W moim przypadku jest to metoda API Mailchimpa o nazwie Add member to segment. Wymaga ona pojedynczej wartości pod zmienną email_address w przesłanym JSONie.

Wartości payloadu zdarzenia są dostępne przez $.detail i użyte w sekcji InputTemplate do konstrukcji oczekiwanej struktury obiektu.

Ostatnia sekcja pozwala nam sparametryzować URL endpointu zdefiniowanego w obiekcie ApiDestination wartościami z payloadu zdarzenia. PathParameterValues przyjmuje tablicę wartości, co oznacza, że w adresie URL możemy zdefiniować więcej niż jeden placeholder. Są one ewaluowane w kolejności, pierwszy element w tablicy odnosi się do pierwszej * w URL, i tak dalej.

Rola - IAM Role

Musimy również zdefiniować Role, która może być przyjęta (assume) przez usługę events.amazonaws.com. Rola ta musi nadawać przywilej events:InvokeApiDestination na zasób MailchimpApiDestination. Pełną definicję roli można znaleźć w przykładowym projekcie na GitHub w pliku serverless.yml.

Przykładowe wdrożenie rozwiązania

Przygotowałem przykładowy projekt wykorzystujący Serverless Framework, więc możesz go wdrożyć na swoim koncie AWS i pobawić się nim.

Musisz sklonować kod, oraz zainstalować zależności:

1
2
3
git clone https://github.com/serverlesspolska/eventbridge-api-destinations-mailchimp.git
cd eventbridge-api-destinations-mailchimp
npm i

To wymaga node.js i npm zainstalowanych na Twojej maszynie.

Ponieważ nie każdy korzysta z Mailchimpa, w projekcie zdefiniowałem drugi cel, który wysyła żądania REST do usługi webhook.site. Jest to darmowa, łatwa w użyciu aplikacja webowa, która będzie działać jako nasz 3rd party endpoint.

Proszę przejdź do webhook.site i skopiuj Your unique URL. Wklej ten adres URL do pliku konfiguracyjnego serverless.yml w linii 38.

Teraz jesteśmy gotowi, aby zdeployować projekt na stage dev za pomocą komendy:

1
sls deploy

(Zakładam, że masz domyślny profil AWS zdefiniowany w ~/.aws/credentials.)

Po udanym deploymencie (może to potrwać kilka minut) można wywołać funkcję Lambda, która wyśle przykładowe zdarzenie Order do naszego EventBusa.

1
sls invoke -f sendOrderEvent -l

W efekcie czego, powinieneś zobaczyć nowe żądanie na stronie webhook.site. (Jeśli nie to odśwież stronę)

Oznacza to, że API Destinations w odpowiedzi na nowe zdarzenie w EventBusie, właśnie wywołało żądanie na zdefiniowany endpoint.

Żądanie otrzymane przez WebHook Site

Jak debugować EventBridge API Destinations?

Jeśli coś źle skonfigurowałeś, lub może Twoje dane uwierzytelniające są złe nie dostaniesz żadnych komunikatów o błędach, nie ma żadnych logów, które mógłbyś przeczytać i spróbować określić co się stało. Wszystko co możesz zrobić, to sprawdzić system 3rd party i zobaczyć, czy żądanie dotarło do niego - dlatego właśnie użyliśmy webhook.site.

A co, jeśli żądanie w ogóle nie trafia do endpointu?

Na szczęście, API Destinations pozwala na użycie kolejek typu Dead Letter Queues (DLQ). Dla każdego Target zdefiniowanego pod AWS::Events::Rule możemy określić kolejkę SQS, która będzie zawierać wiadomości (zdarzenia), które nie mogły być pomyślnie przetworzone przez Target API Destination. Każda wiadomość, która trafia do DLQ jest opatrzona adnotacją z informacją wyjaśniającą powód umieszczenia jej w DLQ.

Oto dwie próbki komunikatów o błędach, które udało mi się uzyskać.
zły Mailchimp API Key Ten został zwrócony, gdy ustawiłem zły Mailchimp API Key.

Brak przywilejów Ten był spowodowany niewłaściwą definicją Roli IAM.

Podsumowanie

Mam nadzieję, że ten artykuł był dla Ciebie pouczający i teraz wiesz jak używać Amazon EventBridge API Destinations w swoich projektach. Jeśli masz jakieś pytania, zadaj je poniżej lub na stronie projektu na GitHubie.

Jestem przekonany, że API Destinations to świetna funkcjonalność, nawet jeśli zajęło mi kilka godzin, aby zrozumieć i wdrożyć ją poprawnie za pierwszym. W dłuższej perspektywie zaoszczędzi mi to znacznie więcej na wdrażaniu i debugowaniu funkcji Lambda, które wywołują endpointy 3rd party. Takie funkcje wydają się być trywialne do napisania, ale w rzeczywistości takie nie są i nie będę za nimi tęsknił. (Jak byś zaimplementował funkcjonalność InvocationRateLimitPerSecond w Lambdzie w taki sposób, żeby nie płacić za czas bezczynności?). Pamiętaj używaj funkcji do transformacji, a nie transportu.

Co jest naprawdę fajne i warte podkreślenia, to fakt, że ta funkcjonalność jest w pełni rozwinięta i dostarczana ze wszystkimi niezbędnymi rzeczami. Co najważniejsze, jest pełne wsparcie CloudFormation, co muszę ze smutkiem przyznać, dotychczas nie zawsze miało miejsce.
Kudos dla zespołu CloudFormation! 🙏

Amazon EventBridge to centralny punkt wielu rozwiązań serverless i cieszę się, że wciąż jest rozwijany. API Destinations to świetny dodatek do tej usługi i mam nadzieję, że w przyszłości pojawią sie kolejne, równie udane.




Cześć

Nazywam się Paweł Zubkiewicz i cieszę się, że tu jesteś!
Od ponad 18 lat profesjonalnie tworzę oprogramowanie, a od 2016 roku pasjonuje się Serverless.
Tą stronę stworzyłem z myślą o Tobie i o nas wszystkich, którzy uważają, że trend serverless trwale zmieni sposób tworzenia oprogramowania.
Więcej o tej stronie...

Kategorie

Pobierz bezpłatny PDF

Poradnik 12 Rzeczy o Serverless

Wybrane artykuły