Korištenje AWS Lambda s API pristupnikom

1. Pregled

AWS Lambda je računalna usluga bez poslužitelja koju pruža Amazon Web Services.

U dva prethodna članka raspravljali smo o tome kako stvoriti AWS Lambda funkciju pomoću Jave, kao i o pristupu DynamoDB iz Lambda funkcije.

U ovom uputstvu ćemo razgovarati kako objaviti Lambda funkciju kao REST krajnju točku, koristeći AWS Gateway.

Detaljno ćemo pogledati sljedeće teme:

  • Osnovni pojmovi i pojmovi API Gateway-a
  • Integracija Lambda funkcija s API pristupnikom pomoću integracije Lambda Proxy
  • Izrada API-ja, njegova struktura i kako mapirati API resurse na Lambda funkcije
  • Uvođenje i ispitivanje API-ja

2. Osnove i pojmovi

API Gateway je potpuno upravljana usluga koja programerima omogućuje stvaranje, objavljivanje, održavanje, nadgledanje i zaštitu API-ja u bilo kojem mjerilu.

Možemo implementirati dosljedno i skalabilno programsko sučelje temeljeno na HTTP-u (koje se nazivaju i RESTful usluge) za pristup pozadinskim uslugama poput Lambda funkcija, daljnjih AWS usluga (npr. EC2, S3, DynamoDB) i bilo kojih HTTP krajnjih točaka.

Značajke uključuju, ali nisu ograničene na:

  • Upravljanje prometom
  • Ovlaštenje i kontrola pristupa
  • Praćenje
  • Upravljanje inačicama API-ja
  • Umanjivanje zahtjeva za sprečavanje napada

Kao i AWS Lambda, API pristupnik se automatski smanjuje i naplaćuje po API pozivu.

Detaljne informacije mogu se naći u službenoj dokumentaciji.

2.1. Pojmovi

API pristupnik je AWS usluga koja podržava stvaranje, postavljanje i upravljanje sučeljem aplikacijskog programiranja RESTful za izlaganje pozadinskih HTTP krajnjih točaka, AWS Lambda funkcija i drugih AWS usluga.

An API API pristupnika je zbirka resursa i metoda koje se mogu integrirati s Lambda funkcijama, drugim AWS uslugama ili HTTP krajnjim točkama u pozadini. API se sastoji od resursa koji čine strukturu API-ja. Svaki API resurs može izložiti jednu ili više API metoda koje moraju imati jedinstvene HTTP glagole.

Da bismo objavili API, moramo stvoriti Uvođenje API-ja i povezati ga s tzv pozornica. Faza je poput snimke u vremenu API-ja. Ako preusmjerimo API, možemo ili ažurirati postojeću fazu ili stvoriti novu. Po tome su moguće različite verzije API-ja istodobno, na primjer a razv pozornica, a test pozornici, pa čak i više produkcijskih verzija, poput v1, v2itd.

Integracija Lambda Proxyja je pojednostavljena konfiguracija za integraciju između Lambda funkcija i API Gatewaya.

API pristupnik šalje cijeli zahtjev kao ulaz u pozadinsku Lambda funkciju. Reagirajući, API pristupnik transformira izlaz Lambda funkcije natrag u sučelni HTTP odgovor.

3. Ovisnosti

Trebat će nam iste ovisnosti kao u članku AWS Lambda koristeći DynamoDB s Javom.

Povrh toga, trebamo i JSON Simple knjižnicu:

 com.googlecode.json-simple json-simple 1.1.1 

4. Razvoj i primjena Lambda funkcija

U ovom ćemo odjeljku razviti i izgraditi svoje Lambda funkcije u Javi, rasporedit ćemo ih pomoću AWS Console i pokrenuti ćemo brzi test.

Kako želimo pokazati osnovne mogućnosti integracije API Gateway-a s Lambda, stvorit ćemo dvije funkcije:

  • Funkcija 1: prima korisni teret od API-ja, koristeći PUT metodu
  • Funkcija 2: pokazuje kako se koristi parametar HTTP puta ili parametar HTTP upita koji dolaze iz API-ja

Što se tiče implementacije, mi ćemo je stvoriti RequestHandler klase, koja ima dvije metode - po jednu za svaku funkciju.

4.1. Model

Prije nego što implementiramo stvarni rukovatelj zahtjevima, hajde da kratko pogledamo naš model podataka:

javna klasa Osoba {private int id; privatni naziv niza; javna osoba (niz json) {Gson gson = novi Gson (); Zahtjev za osobom = gson.fromJson (json, Person.class); this.id = request.getId (); this.name = request.getName (); } javni String toString () {Gson gson = novi GsonBuilder (). setPrettyPrinting (). create (); return gson.toJson (ovo); } // geteri i postavljači}

Naš se model sastoji od jednog jednostavnog Osoba klase, koja ima dva svojstva. Jedini zapaženi dio je Osoba (niz) konstruktor, koji prihvaća JSON String.

4.2. Implementacija klase RequestHandler

Baš kao u članku AWS Lambda With Java, izradit ćemo implementaciju RequestStreamHandler sučelje:

javna klasa APIDemoHandler implementira RequestStreamHandler {private static final String DYNAMODB_TABLE_NAME = System.getenv ("TABLE_NAME"); @Override public void handleRequest (InputStream inputStream, OutputStream outputStream, Context context) baca IOException {// implementacija} public void handleGetByParam (InputStream inputStream, OutputStream outputStream, Context context) baca IOException {// implementacija}}

Kao što vidimo, RequestStreamHander sučelje definira samo jednu metodu, handeRequest (). U svakom slučaju, možemo definirati daljnje funkcije u istoj klasi, kao što smo to učinili ovdje. Druga opcija bila bi stvaranje jedne implementacije RequestStreamHander za svaku funkciju.

U našem konkretnom slučaju prvoga smo odabrali zbog jednostavnosti. Međutim, izbor se mora donositi od slučaja do slučaja, uzimajući u obzir čimbenike kao što su izvedba i održivost koda.

Također smo pročitali naziv naše DynamoDB tablice s TABLE_NAME varijabla okoline. Tu ćemo varijablu definirati kasnije tijekom implementacije.

4.3. Provedba funkcije 1

U našoj prvoj funkciji želimo pokazati kako dobiti korisni teret (na primjer iz zahtjeva PUT ili POST) s API pristupnika:

public void handleRequest (InputStream inputStream, OutputStream outputStream, Context context) baca IOException {JSONParser parser = new JSONParser (); Čitač BufferedReader = novi BufferedReader (novi InputStreamReader (inputStream)); JSONObject responseJson = novi JSONObject (); AmazonDynamoDB klijent = AmazonDynamoDBClientBuilder.defaultClient (); DynamoDB dynamoDb = novi DynamoDB (klijent); isprobajte {JSONObject event = (JSONObject) parser.parse (čitač); if (event.get ("body")! = null) {Person person = new Person ((String) event.get ("body")); dynamoDb.getTable (DYNAMODB_TABLE_NAME) .putItem (new PutItemSpec (). withItem (new Item (). withNumber ("id", person.getId ()) .withString ("name", person.getName ()))); } JSONObject responseBody = novi JSONObject (); responseBody.put ("poruka", "Nova stavka stvorena"); JSONObject headerJson = novi JSONObject (); headerJson.put ("x-custom-header", "moja vrijednost prilagođenog zaglavlja"); responseJson.put ("statusCode", 200); responseJson.put ("zaglavlja", headerJson); responseJson.put ("body", responseBody.toString ()); } catch (ParseException pex) {responseJson.put ("statusCode", 400); responseJson.put ("iznimka", pex); } OutputStreamWriter Writer = novi OutputStreamWriter (outputStream, "UTF-8"); Writer.Write (responseJson.toString ()); pisac.close (); }

Kao što je već spomenuto, API ćemo konfigurirati kasnije da koristi Lambda proxy integraciju. Očekujemo da API pristupnik proslijedi cjeloviti zahtjev funkciji Lambda u InputStream parametar.

Sve što moramo učiniti je odabrati relevantne atribute iz sadržane JSON strukture.

Kao što vidimo, metoda se u osnovi sastoji od tri koraka:

  1. Dohvaćanje tijelo objekt iz našeg ulaznog toka i stvaranje a Osoba objekt iz toga
  2. Pohranjujući to Osoba objekt u DynamoDB tablici
  3. Izgradnja JSON objekta koji može sadržavati nekoliko atributa, poput tijelo za odgovor, prilagođena zaglavlja, kao i HTTP statusni kod

Ovdje valja spomenuti jednu točku: API Gateway očekuje tijelo biti Niz (i za zahtjev i za odgovor).

Kao što očekujemo da ćemo dobiti Niz kao tijelo iz API Gateway-a, emitirali smo tijelo do Niz i inicijalizirati naš Osoba objekt:

Osoba osoba = nova osoba Person ((Niz) event.get ("body"));

API Gateway također očekuje odgovor tijelo biti Niz:

responseJson.put ("body", responseBody.toString ());

Ova tema nije izričito navedena u službenoj dokumentaciji. Međutim, ako pažljivo pogledamo, možemo vidjeti da je atribut body a Niz u oba isječka za zahtjev kao i za odgovor.

Prednost bi trebala biti jasna: čak i ako je JSON format između API Gateway-a i Lambda funkcije, stvarno tijelo može sadržavati običan tekst, JSON, XML ili bilo što drugo. Tada je odgovornost funkcije Lambda za pravilno rukovanje formatom.

Kako će izgledati tijelo zahtjeva i odgovora vidjet ćemo kasnije kada testiramo svoje funkcije u AWS konzoli.

Isto se odnosi i na sljedeće dvije funkcije.

4.4. Provedba funkcije 2

U drugom koraku želimo pokazati kako koristiti parametar puta ili parametar niza upita za dohvaćanje a Osoba stavka iz baze podataka koristeći njezin ID:

javna void handleGetByParam (InputStream inputStream, OutputStream outputStream, Context context) baca IOException {JSONParser parser = new JSONParser (); Čitač BufferedReader = novi BufferedReader (novi InputStreamReader (inputStream)); JSONObject responseJson = novi JSONObject (); AmazonDynamoDB klijent = AmazonDynamoDBClientBuilder.defaultClient (); DynamoDB dynamoDb = novi DynamoDB (klijent); Rezultat stavke = null; isprobajte {JSONObject event = (JSONObject) parser.parse (čitač); JSONObject responseBody = novi JSONObject (); if (event.get ("pathParameters")! = null) {JSONObject pps = (JSONObject) event.get ("pathParameters"); if (pps.get ("id")! = null) {int id = Integer.parseInt ((String) pps.get ("id")); rezultat = dynamoDb.getTable (DYNAMODB_TABLE_NAME) .getItem ("id", id); }} else if (event.get ("queryStringParameters")! = null) {JSONObject qps = (JSONObject) event.get ("queryStringParameters"); if (qps.get ("id")! = null) {int id = Integer.parseInt ((String) qps.get ("id")); rezultat = dynamoDb.getTable (DYNAMODB_TABLE_NAME) .getItem ("id", id); }} if (rezultat! = null) {Osoba osoba = nova Osoba (rezultat.toJSON ()); responseBody.put ("Osoba", osoba); responseJson.put ("statusCode", 200); } else {responseBody.put ("poruka", "Nije pronađena nijedna stavka"); responseJson.put ("statusCode", 404); } JSONObject headerJson = novi JSONObject (); headerJson.put ("x-custom-header", "moja vrijednost prilagođenog zaglavlja"); responseJson.put ("zaglavlja", headerJson); responseJson.put ("body", responseBody.toString ()); } catch (ParseException pex) {responseJson.put ("statusCode", 400); responseJson.put ("iznimka", pex); } OutputStreamWriter Writer = novi OutputStreamWriter (outputStream, "UTF-8"); Writer.Write (responseJson.toString ()); pisac.close (); }

Opet su važna tri koraka:

  1. Provjeravamo je li a pathParameters ili an queryStringParameters niz s iskaznica atribut su prisutni.
  2. Ako pravi, koristimo pripadajuću vrijednost da bismo zatražili a Osoba stavka s tim ID-om iz baze podataka.
  3. Odgovoru dodamo JSON prikaz primljene stavke.

Službena dokumentacija pruža detaljnije objašnjenje ulaznog i izlaznog formata za Proxy Integration.

4.5. Građevinski kod

Opet, možemo jednostavno izgraditi naš kod pomoću Mavena:

mvn čisti paket nijansa: hlad

JAR datoteka će se stvoriti pod cilj mapu.

4.6. Izrada DynamoDB tablice

Tablicu možemo stvoriti kako je objašnjeno u AWS Lambda koristeći DynamoDB s Javom.

Birajmo Osoba kao naziv tablice, iskaznica kao naziv primarnog ključa i Broj kao tip primarnog ključa.

4.7. Postavljanje koda putem AWS konzole

Nakon izgradnje našeg koda i izrade tablice, sada možemo stvoriti funkcije i prenijeti kôd.

To se može učiniti ponavljanjem koraka 1-5 iz članka AWS Lambda s Javom, jednom za svaku od naše dvije metode.

Upotrijebimo sljedeća imena funkcija:

  • StorePersonFunction za handleRequest metoda (funkcija 1)
  • GetPersonByHTTPParamFunction za handleGetByParam metoda (funkcija 2)

Također moramo definirati varijablu okruženja TABLE_NAME s vrijednošću "Osoba".

4.8. Testiranje funkcija

Prije nastavka sa stvarnim dijelom API Gateway-a, možemo pokrenuti brzi test u AWS konzoli, samo da provjerimo rade li naše Lambda funkcije ispravno i mogu li se nositi s formatom Proxy Integration.

Testiranje Lambda funkcije iz AWS konzole djeluje kako je opisano u članku AWS Lambda s Javom.

Međutim, kada kreiramo testni događaj, moramo uzeti u obzir poseban format Proxy Integration, koje naše funkcije očekuju. Možemo koristiti API pristupnik AWS proxy predložak i prilagodite ga našim potrebama ili možemo kopirati i zalijepiti sljedeće događaje:

Za StorePersonFunction, trebali bismo koristiti ovo:

{"body": "{\" id \ ": 1, \" name \ ": \" John Doe \ "}"}

Kao što je već spomenuto, tijelo mora imati tip Niz, čak i ako sadrži JSON strukturu. Razlog je taj što će API pristupnik svoje zahtjeve slati u istom formatu.

Treba vratiti sljedeći odgovor:

{"isBase64Encoded": false, "headers": {"x-custom-header": "my custom header value"}, "body": "{\" message \ ": \" Nova stavka stvorena \ "}", "statusCode": 200}

Ovdje možemo vidjeti da je tijelo našeg odgovora je a Niz, iako sadrži JSON strukturu.

Pogledajmo ulaz za GetPersonByHTTPParamFunction.

Za testiranje funkcionalnosti parametra puta ulaz bi izgledao ovako:

{"pathParameters": {"id": "1"}}

A ulaz za slanje parametra niza upita bio bi:

{"queryStringParameters": {"id": "1"}}

Kao odgovor trebali bismo dobiti sljedeće za oba slučaja:

{"headers": {"x-custom-header": "my custom header value"}, "body": "{\" Person \ ": {\ n \" id \ ": 88, \ n \" naziv \ ": \" John Doe \ "\ n}}", "statusCode": 200}

Opet, tijelo je Niz.

5. Stvaranje i testiranje API-ja

Nakon što smo stvorili i primijenili Lambda funkcije u prethodnom odjeljku, sada možemo stvoriti stvarni API pomoću AWS konzole.

Pogledajmo osnovni tijek rada:

  1. Stvorite API na našem AWS računu.
  2. Dodajte resurs u hijerarhiju resursa API-ja.
  3. Stvorite jednu ili više metoda za resurs.
  4. Postavite integraciju između metode i pripadajuće Lambda funkcije.

Ponovit ćemo korake 2-4 za svaku od naše dvije funkcije u sljedećim odjeljcima.

5.1. Izrada API-ja

Za stvaranje API-a morat ćemo:

  1. Prijavite se na konzolu API Gateway na //console.aws.amazon.com/apigateway
  2. Kliknite "Započni", a zatim odaberite "Novi API"
  3. Upišite ime našeg API-ja (TestAPI) i potvrdite klikom na "Stvori API"

Nakon što smo kreirali API, sada možemo stvoriti strukturu API-ja i povezati je s našim Lambda funkcijama.

5.2. API struktura za funkciju 1

Sljedeći koraci su neophodni za naše StorePersonFunction:

  1. Odaberite nadređenu stavku resursa ispod stabla "Resursi", a zatim na padajućem izborniku "Akcije" odaberite "Stvori resurs". Zatim u oknu "New Child Resource" moramo učiniti sljedeće:
    • Unesite "Osobe" kao ime u polje za tekst za unos "Naziv resursa"
    • Ostavite zadanu vrijednost u polju za unos teksta "Put resursa"
    • Odaberite "Stvori resurs"
  2. Odaberite upravo stvoreni resurs, odaberite "Stvori metodu" s padajućeg izbornika "Akcije" i izvedite sljedeće korake:
    • Odaberite PUT s padajućeg popisa metode HTTP, a zatim odaberite ikonu kvačice da biste spremili izbor
    • Ostavite "Lambda funkciju" kao vrstu integracije i odaberite opciju "Koristi integraciju Lambda Proxy"
    • Odaberite regiju iz "Lambda regije", u kojoj smo prije implementirali svoje Lambda funkcije
    • Tip "StorePersonFunction" u "Lambda funkciji"
  3. Odaberite "Spremi" i potvrdite s "U redu" kada se zatraži "Dodaj dopuštenje za funkciju Lambda"

5.3. API struktura za funkciju 2 - Parametri puta

Koraci za naše parametre dohvaćanja puta su slični:

  1. Odaberi /osobe stavku resursa ispod stabla „Resursi“, a zatim na padajućem izborniku „Akcije“ odaberite „Stvori resurs“. Zatim u oknu New Child Resource moramo učiniti sljedeće:
    • Tip "Osoba" kao ime u tekstnom polju za unos "Naziv resursa"
    • Promijenite polje za tekst "Put resursa" u "{iskaznica}"
    • Odaberite "Stvori resurs"
  2. Odaberite upravo stvoreni resurs, na padajućem izborniku "Akcije" odaberite "Način izrade" i izvedite sljedeće korake:
    • Odaberite GET s padajućeg popisa metode HTTP, a zatim odaberite ikonu kvačice da biste spremili izbor
    • Ostavite "Lambda funkciju" kao vrstu integracije i odaberite opciju "Koristi integraciju Lambda Proxy"
    • Odaberite regiju iz "Lambda regije", u kojoj smo prije implementirali svoje Lambda funkcije
    • Tip “GetPersonByHTTPParamFunction” u "Lambda funkciji"
  3. Odaberite "Spremi" i potvrdite s "U redu" kada se zatraži "Dodaj dopuštenje za funkciju Lambda"

Napomena: ovdje je važno postaviti parametar "Put resursa" na "{iskaznica}", kao naš GetPersonByPathParamFunction očekuje da će ovaj parametar biti imenovan upravo ovako.

5.4. API struktura za funkciju 2 - Parametri niza upita

Koraci za primanje parametara niza upita su malo drugačiji, kao ne moramo stvoriti resurs, već umjesto toga moramo stvoriti parametar upita za iskaznica parametar:

  1. Odaberi /osobe stavku resursa ispod stabla „Resursi“, na padajućem izborniku „Akcije“ odaberite „Način izrade“ i izvedite sljedeće korake:
    • Odaberite GET s padajućeg popisa metode HTTP, a zatim odaberite ikonu kvačice da biste spremili izbor
    • Ostavite "Lambda funkciju" kao vrstu integracije i odaberite opciju "Koristi integraciju Lambda Proxy"
    • Odaberite regiju iz "Lambda regije", u kojoj smo prije implementirali svoje Lambda funkcije
    • Tip “GetPersonByHTTPParamFunction” u “Lambda funkciji”.
  2. Odaberite "Spremi" i potvrdite s "U redu" kada se zatraži "Dodaj dopuštenje za funkciju Lambda"
  3. Odaberite "Zahtjev za metodom" s desne strane i poduzmite sljedeće korake:
    • Proširite popis parametara niza URL-a upita
    • Kliknite "Dodaj niz upita"
    • Tip "iskaznica" u polju za ime i odaberite ikonu kvačice za spremanje
    • Označite potvrdni okvir "Obavezno"
    • Kliknite simbol olovke pored "Zahtjev za provjeru valjanosti" na vrhu ploče, odaberite "Provjeri parametre niza upita i zaglavlja" i odaberite ikonu kvačice

Napomena: Važno je postaviti parametar "Niz upita" na "iskaznica", kao naš GetPersonByHTTPParamFunction očekuje da će ovaj parametar biti imenovan upravo ovako.

5.5. Testiranje API-ja

Naš API je sada spreman, ali još nije javan. Prije nego što ga objavimo, prvo želimo pokrenuti brzi test s konzole.

Za to možemo odabrati odgovarajuću metodu koja će se testirati na stablu „Resursi“ i kliknuti na gumb „Test“. Na sljedećem zaslonu možemo unijeti svoj ulaz, jer bismo ga poslali s klijentom putem HTTP-a.

Za StorePersonFunction, u polje "Tijelo zahtjeva" moramo upisati sljedeću strukturu:

{"id": 2, "name": "Jane Doe"}

Za GetPersonByHTTPParamFunction s parametrima puta, moramo tipkati 2 kao vrijednost u polje "{id}" pod "Put".

Za GetPersonByHTTPParamFunction s parametrima niza upita moramo tipkati id = 2 kao vrijednost u polje „{persons}“ u odjeljku „Nizovi upita“.

5.6. Uvođenje API-ja

Do sada naš API nije bio javan i stoga je bio dostupan samo s AWS konzole.

Kao što je već spomenuto, kad rasporedimo API, moramo ga povezati sa fazom, koja je poput snimke u vremenu API-ja. Ako preusmjerimo API, možemo ili ažurirati postojeću fazu ili stvoriti novu.

Pogledajmo kako će izgledati shema URL-a za naš API:

//{restapi-id}.execute-api.{region}.amazonaws.com/{stageName}

Za implementaciju su potrebni sljedeći koraci:

  1. Odaberite određeni API u navigacijskom oknu "API-ji"
  2. Odaberite "Akcije" u navigacijskom oknu Resursi i odaberite "Implementiraj API" s padajućeg izbornika "Akcije"
  3. Odaberite "[Nova faza]" s padajućeg izbornika "Faza implementacije", upišite "test" u "Naziv faze" i po želji pružiti opis faze i raspoređivanja
  4. Pokrenite implementaciju odabirom "Rasporedi"

Nakon zadnjeg koraka, konzola će pružiti korijenski URL API-ja, na primjer, //0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test.

5.7. Pozivanje na krajnju točku

Kako je API sada javan, možemo ga nazvati pomoću bilo kojeg HTTP klijenta kojeg želimo.

S kovrča, pozivi bi izgledali kako slijedi.

StorePersonFunction:

curl -X PUT '//0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons' \ -H 'content-type: application / json' \ -d '{"id": 3, "name": "Richard Roe"} '

GetPersonByHTTPParamFunction za parametre puta:

curl -X GET '//0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons/3' \ -H 'vrsta sadržaja: application / json'

GetPersonByHTTPParamFunction za parametre niza upita:

curl -X GET '//0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons?id=3' \ -H 'vrsta sadržaja: application / json'

6. Zaključak

U ovom smo članku pogledali kako učiniti AWS Lambda funkcije dostupnim kao REST krajnje točke, koristeći AWS API Gateway.

Istražili smo osnovne koncepte i terminologiju API Gateway-a i naučili kako integrirati Lambda funkcije pomoću Lambda Proxy Integration.

Napokon smo vidjeli kako stvoriti, implementirati i testirati API.

Kao i obično, sav kôd za ovaj članak dostupan je na GitHubu.


$config[zx-auto] not found$config[zx-overlay] not found