Bruke AWS Lambda med API Gateway

1. Oversikt

AWS Lambda er en serverløs datatjeneste levert av Amazon Web Services.

I to tidligere artikler diskuterte vi hvordan du oppretter en AWS Lambda-funksjon ved hjelp av Java, samt hvordan du får tilgang til DynamoDB fra en Lambda-funksjon.

I denne opplæringen vil vi diskutere hvordan du publiserer en Lambda-funksjon som et REST-sluttpunkt, ved hjelp av AWS Gateway.

Vi vil se nærmere på følgende emner:

  • Grunnleggende konsepter og vilkår for API Gateway
  • Integrering av Lambda-funksjoner med API Gateway ved hjelp av Lambda Proxy-integrasjon
  • Oppretting av et API, dets struktur og hvordan du kan kartlegge API-ressursene på Lambda-funksjoner
  • Implementering og test av API

2. Grunnleggende og vilkår

API Gateway er en fullt administrert tjeneste som gjør det mulig for utviklere å lage, publisere, vedlikeholde, overvåke og sikre APIer i alle størrelser.

Vi kan implementere et konsistent og skalerbart HTTP-basert programmeringsgrensesnitt (også referert til som RESTful-tjenester) for å få tilgang til backend-tjenester som Lambda-funksjoner, ytterligere AWS-tjenester (f.eks. EC2, S3, DynamoDB) og eventuelle HTTP-sluttpunkter.

Funksjonene inkluderer, men er ikke begrenset til:

  • Trafikkstyring
  • Autorisasjon og tilgangskontroll
  • Overvåkning
  • API-versjonsadministrasjon
  • Begrensning av forespørsler om å forhindre angrep

I likhet med AWS Lambda skaleres API Gateway automatisk ut og faktureres per API-anrop.

Detaljert informasjon finner du i den offisielle dokumentasjonen.

2.1. Vilkår

API Gateway er en AWS-tjeneste som støtter opprette, distribuere og administrere et RESTful applikasjonsprogrammeringsgrensesnitt for å eksponere backend HTTP-endepunkter, AWS Lambda-funksjoner og andre AWS-tjenester.

An API Gateway API er en samling ressurser og metoder som kan integreres med Lambda-funksjoner, andre AWS-tjenester eller HTTP-endepunkter i backend. API-en består av ressurser som danner API-strukturen. Hver API-ressurs kan avsløre en eller flere API-metoder som må ha unike HTTP-verb.

For å publisere en API, må vi opprette en API-distribusjon og knytte den til en såkalt scene. En scene er som et øyeblikksbilde av API-en. Hvis vi distribuerer en API på nytt, kan vi enten oppdatere en eksisterende scene eller opprette en ny. På den måten er forskjellige versjoner av en API samtidig mulig, for eksempel en dev scene, a test scenen, og til og med flere produksjonsversjoner, som v1, v2, etc.

Lambda Proxy integrasjon er en forenklet konfigurasjon for integrasjonen mellom Lambda-funksjoner og API Gateway.

API Gateway sender hele forespørselen som en inngang til en backend Lambda-funksjon. Responsmessig forvandler API Gateway Lambda-funksjonens utgang tilbake til en frontend HTTP-respons.

3. Avhengigheter

Vi trenger de samme avhengighetene som i AWS Lambda ved hjelp av DynamoDB With Java-artikkelen.

På toppen av det trenger vi også JSON Simple-biblioteket:

 com.googlecode.json-simple json-simple 1.1.1 

4. Utvikling og implementering av Lambda-funksjonene

I denne delen vil vi utvikle og bygge våre Lambda-funksjoner i Java, vi vil distribuere den ved hjelp av AWS Console, og vi kjører en rask test.

Da vi vil demonstrere de grunnleggende mulighetene for å integrere API Gateway med Lambda, oppretter vi to funksjoner:

  • Funksjon 1: mottar en nyttelast fra API, ved hjelp av en PUT-metode
  • Funksjon 2: demonstrerer hvordan du bruker en HTTP-sti-parameter eller HTTP-spørringsparameter som kommer fra API

Implementeringsmessig lager vi en RequestHandler klasse, som har to metoder - en for hver funksjon.

4.1. Modell

Før vi implementerer selve forespørselsbehandleren, la oss raskt se på datamodellen vår:

offentlig klasse Person {privat int id; privat strengnavn; offentlig person (streng json) {Gson gson = ny Gson (); Personforespørsel = gson.fromJson (json, Person.class); this.id = request.getId (); this.name = request.getName (); } offentlig String toString () {Gson gson = ny GsonBuilder (). setPrettyPrinting (). create (); returner gson.toJson (dette); } // getters og setters}

Modellen vår består av en enkel Person klasse, som har to egenskaper. Den eneste bemerkelsesverdige delen er Person (streng) konstruktør, som godtar en JSON-streng.

4.2. Implementering av RequestHandler-klassen

Akkurat som i AWS Lambda With Java-artikkelen, lager vi en implementering av RequestStreamHandler grensesnitt:

offentlig klasse APIDemoHandler implementerer RequestStreamHandler {privat statisk sluttstreng DYNAMODB_TABLE_NAME = System.getenv ("TABLE_NAME"); @Override public void handleRequest (InputStream inputStream, OutputStream outputStream, Context context) kaster IOException {// implementering} public void handleGetByParam (InputStream inputStream, OutputStream outputStream, Context context) kaster IOException {// implementering}}

Som vi kan se, er RequestStreamHander grensesnitt definerer bare en metode, handeRequest (). Uansett kan vi definere flere funksjoner i samme klasse, som vi har gjort her. Et annet alternativ ville være å lage en implementering av RequestStreamHander for hver funksjon.

I vårt spesifikke tilfelle valgte vi førstnevnte for enkelhet. Valget må imidlertid tas fra sak til sak, idet det tas hensyn til faktorer som ytelse og vedlikehold av kode.

Vi leser også navnet på DynamoDB-tabellen fra TABLE_NAME miljøvariabel. Vi definerer den variabelen senere under distribusjonen.

4.3. Implementering av funksjon 1

I vår første funksjon ønsker vi å demonstrere hvordan få tak i en nyttelast (som fra en PUT- eller POST-forespørsel) fra API Gateway:

public void handleRequest (InputStream inputStream, OutputStream outputStream, Context context) kaster IOException {JSONParser parser = new JSONParser (); BufferedReader reader = ny BufferedReader (ny InputStreamReader (inputStream)); JSONObject responsJson = ny JSONObject (); AmazonDynamoDB-klient = AmazonDynamoDBClientBuilder.defaultClient (); DynamoDB dynamoDb = ny DynamoDB (klient); prøv {JSONObject event = (JSONObject) parser.parse (reader); 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 = ny JSONObject (); responseBody.put ("melding", "Nytt element opprettet"); JSONObject headerJson = new JSONObject (); headerJson.put ("x-custom-header", "my custom header value"); responseJson.put ("statusCode", 200); responseJson.put ("headers", headerJson); responseJson.put ("body", responseBody.toString ()); } fange (ParseException pex) {responsJson.put ("statusCode", 400); responseJson.put ("unntak", pex); } OutputStreamWriter-forfatter = ny OutputStreamWriter (outputStream, "UTF-8"); writer.write (responseJson.toString ()); writer.close (); }

Som diskutert tidligere, konfigurerer vi API senere for å bruke Lambda proxy-integrasjon. Vi forventer at API Gateway vil sende den fullstendige forespørselen til Lambda-funksjonen i InputStream parameter.

Alt vi trenger å gjøre er å velge de aktuelle attributtene fra den inneholdte JSON-strukturen.

Som vi kan se, består metoden i utgangspunktet av tre trinn:

  1. Henter kropp objekt fra inngangsstrømmen vår og skape et Person objekt fra det
  2. Lagrer det Person objekt i en DynamoDB-tabell
  3. Å bygge et JSON-objekt, som kan inneholde flere attributter, som en kropp for svaret, tilpassede overskrifter, samt en HTTP-statuskode

Et poeng det er verdt å nevne her: API Gateway forventer at kropp å være en String (for både forespørsel og svar).

Som vi forventer å få en String som kropp fra API Gateway, kastet vi kropp til String og initialiser vår Person gjenstand:

Personperson = ny person ((streng) event.get ("kropp"));

API Gateway forventer også svaret kropp å være en String:

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

Dette emnet er ikke nevnt eksplisitt i den offisielle dokumentasjonen. Men hvis vi ser nøye på, kan vi se at kroppsattributtet er en String i begge utdragene for forespørselen så vel som for svaret.

Fordelen skal være klar: selv om JSON er formatet mellom API Gateway og Lambda-funksjonen, kan selve brødteksten inneholde ren tekst, JSON, XML eller hva som helst. Det er da Lambda-funksjonens ansvar å håndtere formatet riktig.

Vi får se hvordan forespørselen og svarorganet ser ut senere når vi tester funksjonene våre i AWS-konsollen.

Det samme gjelder også de følgende to funksjonene.

4.4. Implementering av funksjon 2

I et andre trinn ønsker vi å demonstrere hvordan du bruker en styparameter eller en spørringsstrengparameter for å hente en Person element fra databasen ved hjelp av IDen:

public void handleGetByParam (InputStream inputStream, OutputStream outputStream, Context context) kaster IOException {JSONParser parser = new JSONParser (); BufferedReader reader = ny BufferedReader (ny InputStreamReader (inputStream)); JSONObject responsJson = ny JSONObject (); AmazonDynamoDB-klient = AmazonDynamoDBClientBuilder.defaultClient (); DynamoDB dynamoDb = ny DynamoDB (klient); Vareresultat = null; prøv {JSONObject event = (JSONObject) parser.parse (reader); JSONObject responseBody = ny JSONObject (); hvis (event.get ("pathParameters")! = null) {JSONObject pps = (JSONObject) event.get ("pathParameters"); hvis (pps.get ("id")! = null) {int id = Integer.parseInt ((String) pps.get ("id")); resultat = dynamoDb.getTable (DYNAMODB_TABLE_NAME) .getItem ("id", id); }} annet hvis (event.get ("queryStringParameters")! = null) {JSONObject qps = (JSONObject) event.get ("queryStringParameters"); hvis (qps.get ("id")! = null) {int id = Integer.parseInt ((String) qps.get ("id")); resultat = dynamoDb.getTable (DYNAMODB_TABLE_NAME) .getItem ("id", id); }} hvis (resultat! = null) {Person person = new Person (result.toJSON ()); responseBody.put ("Person", person); responseJson.put ("statusCode", 200); } annet {responsBody.put ("melding", "Ingen gjenstand funnet"); responseJson.put ("statusCode", 404); } JSONObject headerJson = new JSONObject (); headerJson.put ("x-custom-header", "my custom header value"); responseJson.put ("headers", headerJson); responseJson.put ("body", responseBody.toString ()); } fange (ParseException pex) {responsJson.put ("statusCode", 400); responseJson.put ("unntak", pex); } OutputStreamWriter-forfatter = ny OutputStreamWriter (outputStream, "UTF-8"); writer.write (responseJson.toString ()); writer.close (); }

Igjen er tre trinn relevante:

  1. Vi sjekker om a pathParameters eller en queryStringParameters array med en id attributt er til stede.
  2. Hvis ekte, bruker vi tilhørende verdi for å be om en Person element med den IDen fra databasen.
  3. Vi legger til en JSON-representasjon av mottatt vare i svaret.

Den offisielle dokumentasjonen gir en mer detaljert forklaring av inputformat og outputformat for Proxy Integration.

4.5. Byggekode

Igjen kan vi bare bygge koden vår ved hjelp av Maven:

mvn ren pakkeskygge: skygge

JAR-filen blir opprettet under mål mappe.

4.6. Opprette DynamoDB-tabellen

Vi kan lage tabellen som forklart i AWS Lambda ved hjelp av DynamoDB With Java.

La oss velge Person som tabellnavn, id som primærnøkkelnavn, og Nummer som type primærnøkkel.

4.7. Implementering av kode via AWS-konsoll

Etter å ha bygget koden vår og opprettet tabellen, kan vi nå opprette funksjonene og laste opp koden.

Dette kan gjøres ved å gjenta trinn 1-5 fra AWS Lambda med Java-artikkelen, en gang for hver av våre to metoder.

La oss bruke følgende funksjonsnavn:

  • StorePersonFunction for handleRequest metode (funksjon 1)
  • GetPersonByHTTPParamFunction for handleGetByParam metode (funksjon 2)

Vi må også definere en miljøvariabel TABLE_NAME med verdi "Person".

4.8. Testing av funksjonene

Før vi fortsetter med den faktiske API Gateway-delen, kan vi kjøre en rask test i AWS-konsollen, bare for å sjekke at Lambda-funksjonene kjører riktig og kan håndtere Proxy Integration-formatet.

Å teste en Lambda-funksjon fra AWS-konsollen fungerer som beskrevet i AWS Lambda med Java-artikkelen.

Derimot, når vi oppretter en testhendelse, må vi vurdere det spesielle Proxy Integration-formatet, som funksjonene våre forventer. Vi kan enten bruke API Gateway AWS Proxy mal og tilpasse det etter våre behov, eller vi kan kopiere og lime inn følgende hendelser:

For StorePersonFunction, bør vi bruke dette:

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

Som diskutert før, kropp må ha typen String, selv om den inneholder en JSON-struktur. Årsaken er at API Gateway vil sende sine forespørsler i samme format.

Følgende svar skal returneres:

{"isBase64Encoded": false, "headers": {"x-custom-header": "my custom header value"}, "body": "{\" message \ ": \" Nytt element opprettet \ "}", "statusCode": 200}

Her kan vi se at kropp av vårt svar er en String, selv om den inneholder en JSON-struktur.

La oss se på inngangen for GetPersonByHTTPParamFunction.

For å teste baneparameterfunksjonaliteten, vil inngangen se slik ut:

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

Og inngangen for å sende en spørringsstrengparameter vil være:

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

Som et svar, bør vi få følgende for begge tilfelle metoder:

{"headers": {"x-custom-header": "min egendefinerte topptekstverdi"}, "body": "{\" Person \ ": {\ n \" id \ ": 88, \ n \" name \ ": \" John Doe \ "\ n}}", "statusCode": 200}

Igjen, den kropp er en String.

5. Opprette og teste API

Etter at vi opprettet og distribuerte Lambda-funksjonene i forrige avsnitt, vi kan nå lage den faktiske API-en ved hjelp av AWS-konsollen.

La oss se på den grunnleggende arbeidsflyten:

  1. Opprett et API i AWS-kontoen vår.
  2. Legg til en ressurs i ressurshierarkiet til API.
  3. Lag en eller flere metoder for ressursen.
  4. Sett opp integrasjonen mellom en metode og tilhørende Lambda-funksjon.

Vi gjentar trinn 2-4 for hver av våre to funksjoner i de følgende avsnittene.

5.1. Opprette API

For å opprette API-en må vi:

  1. Logg på API Gateway-konsollen på //console.aws.amazon.com/apigateway
  2. Klikk på "Kom i gang" og velg deretter "Ny API"
  3. Skriv inn navnet på API-en (TestAPI) og bekreft ved å klikke på “Create API”

Etter å ha opprettet APIen, kan vi nå opprette API-strukturen og koble den til våre Lambda-funksjoner.

5.2. API-struktur for funksjon 1

Følgende trinn er nødvendige for våre StorePersonFunction:

  1. Velg overordnet ressurselement under "Ressurser" -treet, og velg deretter "Opprett ressurs" fra rullegardinmenyen "Handlinger". Deretter må vi gjøre følgende i "New Child Resource" -ruten:
    • Skriv inn "Personer" som et navn i "Ressursnavn" -inntastingsfeltet
    • La standardverdien ligge i "Resource Path" -feltet
    • Velg "Opprett ressurs"
  2. Velg den nettopp opprettede ressursen, velg "Opprett metode" fra rullegardinmenyen "Handlinger", og utfør følgende trinn:
    • Velg PUT fra rullegardinlisten HTTP-metode, og velg deretter hakemerkeikonet for å lagre valget
    • La "Lambda-funksjon" være som integrasjonstype, og velg "Bruk Lambda Proxy-integrering"
    • Velg regionen fra "Lambda Region", der vi distribuerte Lambda-funksjonene våre tidligere
    • Type “StorePersonFunction” i “Lambda-funksjon”
  3. Velg "Lagre" og bekreft med "OK" når du blir bedt om "Legg tillatelse til Lambda-funksjonen"

5.3. API-struktur for funksjon 2 - baneparametere

Trinnene for å hente baneparametere er like:

  1. Velg /personer ressurselement under "Ressurser" -treet, og velg deretter "Opprett ressurs" fra rullegardinmenyen "Handlinger". Deretter må vi gjøre følgende i New Child Resource-ruten:
    • Type "Person" som et navn i "Ressursnavn" -inntastingsfeltet
    • Endre inntastingsfeltet "Ressurebane" til “{Id}”
    • Velg "Opprett ressurs"
  2. Velg den nettopp opprettede ressursen, velg “Opprett metode” fra rullegardinmenyen “Handlinger”, og utfør følgende trinn:
    • Velg GET fra rullegardinlisten HTTP-metode, og velg deretter hakeikonet for å lagre valget
    • La "Lambda-funksjon" være som integrasjonstype, og velg "Bruk Lambda Proxy-integrering"
    • Velg regionen fra "Lambda Region", der vi distribuerte Lambda-funksjonene våre tidligere
    • Type “GetPersonByHTTPParamFunction” i “Lambda-funksjon”
  3. Velg "Lagre" og bekreft med "OK" når du blir bedt om "Legg tillatelse til Lambda-funksjonen"

Merk: det er viktig her å sette parameteren "Ressurssti" til “{Id}”, som vår GetPersonByPathParamFunction forventer at denne parameteren blir navngitt nøyaktig slik.

5.4. API-struktur for funksjon 2 - spørringsstrengparametere

Trinnene for å motta spørringsstrengparametere er litt forskjellige, som vi trenger ikke å opprette en ressurs, men i stedet for å opprette en spørringsparameter for id parameter:

  1. Velg / personer ressurselement under "Ressurser" -treet, velg "Opprett metode" fra rullegardinmenyen "Handlinger", og utfør følgende trinn:
    • Velg GET fra rullegardinlisten HTTP-metode, og velg deretter hakeikonet for å lagre valget
    • La "Lambda-funksjon" være som integrasjonstype, og velg "Bruk Lambda Proxy-integrering"
    • Velg regionen fra "Lambda Region", der vi distribuerte Lambda-funksjonene våre tidligere
    • Type “GetPersonByHTTPParamFunction” i “Lambda-funksjon”.
  2. Velg "Lagre" og bekreft med "OK" når du blir bedt om "Legg tillatelse til Lambda-funksjonen"
  3. Velg “Method Request” til høyre og utfør følgende trinn:
    • Utvid listen over URL-spørsmålsparametere
    • Klikk på “Legg til spørringsstreng”
    • Type “Id” i navnefeltet, og velg avkrysningsmerket for å lagre
    • Merk av for "Påkrevd"
    • Klikk på pennesymbolet ved siden av "Request validator" øverst i panelet, velg "Validate query string parameters and headers", og velg hakeikonet

Merk: Det er viktig å sette parameteren "Query String" til “Id”, som vår GetPersonByHTTPParamFunction forventer at denne parameteren blir navngitt nøyaktig slik.

5.5. Testing av API

API-en vår er nå klar, men den er ikke offentlig ennå. Før vi publiserer den, vil vi først kjøre en rask test fra konsollen.

For det kan vi velge den respektive metoden som skal testes i “Resources” -treet og klikke på “Test” -knappen. På det følgende skjermbildet kan vi skrive inn innspillene våre, slik vi sender det med en klient via HTTP.

Til StorePersonFunction, må vi skrive inn følgende struktur i feltet "Request Body":

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

For GetPersonByHTTPParamFunction med baneparametere, må vi skrive 2 som en verdi i “{id}” -feltet under “Sti”.

For GetPersonByHTTPParamFunction med parametere for spørringsstreng, må vi skrive id = 2 som en verdi i “{persons}” -feltet under “Query Strings”.

5.6. Implementering av API

Hittil var API-en vår ikke offentlig, og var derfor bare tilgjengelig fra AWS-konsollen.

Som diskutert tidligere, når vi distribuerer en API, må vi knytte den til en scene, som er som et øyeblikksbilde i tid av API. Hvis vi distribuerer en API på nytt, kan vi enten oppdatere en eksisterende scene eller opprette en ny.

La oss se hvordan URL-skjemaet for API-et vårt vil se ut:

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

Følgende trinn kreves for distribusjon:

  1. Velg det aktuelle API-et i navigasjonsruten “APIer”
  2. Velg "Handlinger" i navigasjonsruten Ressurser og velg "Distribuer API" fra rullegardinmenyen "Handlinger"
  3. Velg "[New Stage]" fra rullegardinmenyen "Deployment stage" "test" i “Stage name”, og eventuelt gi en beskrivelse av scenen og distribusjonen
  4. Utløs distribusjonen ved å velge “Distribuere”

Etter det siste trinnet vil konsollen gi rot-URL til API-et, for eksempel //0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test.

5.7. Påkalle sluttpunktet

Siden API er offentlig nå, vi kan kalle det ved hjelp av hvilken som helst HTTP-klient vi ønsker.

Med krøllvil samtalene se ut som følger.

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 for baneparametere:

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

GetPersonByHTTPParamFunction for søkestrengparametere:

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

6. Konklusjon

I denne artikkelen så vi hvordan vi kunne gjøre AWS Lambda-funksjoner tilgjengelige som REST-endepunkter ved hjelp av AWS API Gateway.

Vi utforsket de grunnleggende konseptene og terminologien til API Gateway, og vi lærte å integrere Lambda-funksjoner ved hjelp av Lambda Proxy Integration.

Til slutt så vi hvordan vi skulle lage, distribuere og teste en API.

Som vanlig er all koden for denne artikkelen tilgjengelig på GitHub.


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