Brug af AWS Lambda med API Gateway

1. Oversigt

AWS Lambda er en serverløs computertjeneste leveret af Amazon Web Services.

I to tidligere artikler diskuterede vi, hvordan man opretter en AWS Lambda-funktion ved hjælp af Java, samt hvordan man får adgang til DynamoDB fra en Lambda-funktion.

I denne vejledning diskuterer vi hvordan man udgiver en Lambda-funktion som et REST-slutpunkt ved hjælp af AWS Gateway.

Vi får et detaljeret kig på følgende emner:

  • Grundlæggende koncepter og vilkår for API Gateway
  • Integration af Lambda-funktioner med API Gateway ved hjælp af Lambda Proxy-integration
  • Oprettelse af en API, dens struktur og hvordan man kortlægger API-ressourcerne på Lambda-funktioner
  • Implementering og test af API

2. Grundlæggende og vilkår

API Gateway er en fuldt administreret tjeneste, der giver udviklere mulighed for at oprette, udgive, vedligeholde, overvåge og sikre API'er i enhver skala.

Vi kan implementere en ensartet og skalerbar HTTP-baseret programmeringsgrænseflade (også kaldet RESTful-tjenester) for at få adgang til backend-tjenester som Lambda-funktioner, yderligere AWS-tjenester (f.eks. EC2, S3, DynamoDB) og eventuelle HTTP-slutpunkter.

Funktioner inkluderer, men er ikke begrænset til:

  • Trafikstyring
  • Autorisation og adgangskontrol
  • Overvågning
  • API version management
  • Begrænsning af anmodninger om at forhindre angreb

Ligesom AWS Lambda skaleres API Gateway automatisk ud og faktureres pr. API-opkald.

Detaljerede oplysninger kan findes i den officielle dokumentation.

2.1. Vilkår

API-gateway er en AWS-tjeneste, der understøtter oprettelse, implementering og styring af en RESTful applikationsprogrammeringsgrænseflade til eksponering af backend HTTP-slutpunkter, AWS Lambda-funktioner og andre AWS-tjenester.

En API Gateway API er en samling af ressourcer og metoder, der kan integreres med Lambda-funktioner, andre AWS-tjenester eller HTTP-slutpunkter i backend. API'en består af ressourcer, der danner API-strukturen. Hver API-ressource kan eksponere en eller flere API-metoder, der skal have unikke HTTP-verber.

For at udgive en API skal vi oprette en API-implementering og knytte det til en såkaldt scene. En scene er som et øjebliksbillede af API'ens tid. Hvis vi omplacerer en API, kan vi enten opdatere en eksisterende fase eller oprette en ny. Dermed er forskellige versioner af en API på samme tid mulige, for eksempel en dev etape, en prøve scene, og endda flere produktionsversioner, ligesom v1, v2, etc.

Lambda Proxy integration er en forenklet konfiguration til integration mellem Lambda-funktioner og API Gateway.

API Gateway sender hele anmodningen som et input til en backend Lambda-funktion. Svarmæssigt omdanner API Gateway Lambda-funktionens output tilbage til et frontend HTTP-svar.

3. Afhængigheder

Vi har brug for de samme afhængigheder som i AWS Lambda ved hjælp af DynamoDB With Java-artiklen.

Derudover har vi også brug for JSON Simple-biblioteket:

 com.googlecode.json-simple json-simple 1.1.1 

4. Udvikling og implementering af Lambda-funktionerne

I dette afsnit udvikler og bygger vi vores Lambda-funktioner i Java, vi implementerer det ved hjælp af AWS Console, og vi kører en hurtig test.

Da vi vil demonstrere de grundlæggende muligheder for at integrere API Gateway med Lambda, opretter vi to funktioner:

  • Funktion 1: modtager en nyttelast fra API'en ved hjælp af en PUT-metode
  • Funktion 2: demonstrerer, hvordan man bruger en HTTP-sti-parameter eller HTTP-forespørgselsparameter, der kommer fra API'en

Implementeringsmæssigt opretter vi en RequestHandler klasse, som har to metoder - en for hver funktion.

4.1. Model

Før vi implementerer den egentlige anmodningshåndterer, lad os hurtigt se på vores datamodel:

offentlig klasse person {privat int id; privat strengnavn; offentlig person (String json) {Gson gson = ny Gson (); Personanmodning = gson.fromJson (json, Person.class); this.id = anmodning.getId (); dette.navn = anmodning.getnavn (); } offentlig String toString () {Gson gson = ny GsonBuilder (). setPrettyPrinting (). create (); returner gson.toJson (dette); } // getters og setters}

Vores model består af en enkel Person klasse, som har to egenskaber. Den eneste bemærkelsesværdige del er Person (streng) konstruktør, som accepterer en JSON-streng.

4.2. Implementering af RequestHandler-klassen

Ligesom i AWS Lambda With Java-artiklen opretter vi en implementering af RequestStreamHandler grænseflade:

offentlig klasse APIDemoHandler implementerer RequestStreamHandler {privat statisk endelig streng 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 interface definerer kun en metode, handeRequest (). Under alle omstændigheder kan vi definere yderligere funktioner i samme klasse, som vi har gjort her. En anden mulighed ville være at oprette en implementering af RequestStreamHander for hver funktion.

I vores specifikke tilfælde valgte vi førstnævnte for enkelhed. Valget skal dog foretages fra sag til sag under hensyntagen til faktorer som ydeevne og vedligeholdelse af kode.

Vi læser også navnet på vores DynamoDB-tabel fra TABLE_NAME miljøvariabel. Vi definerer den variabel senere under implementeringen.

4.3. Implementering af funktion 1

I vores første funktion vil vi demonstrere hvordan man får en nyttelast (som fra en PUT- eller POST-anmodning) fra API Gateway:

public void handleRequest (InputStream inputStream, OutputStream outputStream, Context context) kaster IOException {JSONParser parser = ny JSONParser (); BufferedReader-læser = ny BufferedReader (ny InputStreamReader (inputStream)); JSONObject responsJson = nyt 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 responsBody = ny JSONObject (); responseBody.put ("besked", "Nyt element oprettet"); JSONObject headerJson = ny 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 ("undtagelse", pex); } OutputStreamWriter-forfatter = ny OutputStreamWriter (outputStream, "UTF-8"); writer.write (responseJson.toString ()); writer.close (); }

Som diskuteret tidligere konfigurerer vi API'et senere til at bruge Lambda-proxyintegration. Vi forventer, at API Gateway videresender den komplette anmodning til Lambda-funktionen i InputStream parameter.

Alt, hvad vi skal gøre er at vælge de relevante attributter fra den indeholdte JSON-struktur.

Som vi kan se, består metoden dybest set i tre trin:

  1. Henter legeme objekt fra vores inputstrøm og skabe et Person objekt fra det
  2. Gemme det Person objekt i en DynamoDB-tabel
  3. Opbygning af et JSON-objekt, der kan indeholde flere attributter, som f.eks legeme til svaret, brugerdefinerede overskrifter samt en HTTP-statuskode

Et punkt værd at nævne her: API Gateway forventer legeme at være en Snor (for både anmodning og svar).

Som vi forventer at få en Snor som legeme fra API Gateway kaster vi legeme til Snor og initialiser vores Person objekt:

Person person = ny person ((streng) event.get ("body"));

API Gateway forventer også svaret legeme at være en Snor:

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

Dette emne er ikke nævnt eksplicit i den officielle dokumentation. Men hvis vi ser tæt på, kan vi se, at kropsattributten er en Snor i begge uddrag til anmodningen såvel som til svaret.

Fordelen skal være klar: selvom JSON er formatet mellem API Gateway og Lambda-funktionen, kan selve kroppen indeholde almindelig tekst, JSON, XML eller hvad som helst. Det er derefter Lambda-funktionens ansvar at håndtere formatet korrekt.

Vi får se, hvordan anmodnings- og svarorganet ser ud senere, når vi tester vores funktioner i AWS-konsollen.

Det samme gælder også for de følgende to funktioner.

4.4. Implementering af funktion 2

I et andet trin ønsker vi at demonstrere hvordan man bruger en styparameter eller en forespørgselsstrengparameter for at hente en Person element fra databasen ved hjælp af dets ID:

public void handleGetByParam (InputStream inputStream, OutputStream outputStream, Context context) kaster IOException {JSONParser parser = ny JSONParser (); BufferedReader-læser = ny BufferedReader (ny InputStreamReader (inputStream)); JSONObject responsJson = nyt 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); }} ellers 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 = ny person (result.toJSON ()); responseBody.put ("Person", person); responseJson.put ("statusCode", 200); } andet {responsBody.put ("meddelelse", "Ingen genstande fundet"); responseJson.put ("statusCode", 404); } JSONObject headerJson = ny 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 ("undtagelse", pex); } OutputStreamWriter-forfatter = ny OutputStreamWriter (outputStream, "UTF-8"); writer.write (responseJson.toString ()); writer.close (); }

Igen er tre trin relevante:

  1. Vi kontrollerer, om en pathParameters eller en queryStringParameters matrix med en id attribut er til stede.
  2. Hvis rigtigt, bruger vi tilhørende værdi til at anmode om en Person element med det ID fra databasen.
  3. Vi tilføjer en JSON-repræsentation af den modtagne vare til svaret.

Den officielle dokumentation giver en mere detaljeret forklaring af inputformat og outputformat til Proxy Integration.

4.5. Bygningskodeks

Igen kan vi simpelthen bygge vores kode ved hjælp af Maven:

mvn ren pakke skygge: skygge

JAR-filen oprettes under mål folder.

4.6. Oprettelse af DynamoDB-tabellen

Vi kan oprette tabellen som forklaret i AWS Lambda ved hjælp af DynamoDB med Java.

Lad os vælge Person som tabelnavn, id som primært nøglenavn, og Nummer som type af den primære nøgle.

4.7. Implementering af kode via AWS-konsol

Efter at have bygget vores kode og oprettet tabellen kan vi nu oprette funktionerne og uploade koden.

Dette kan gøres ved at gentage trin 1-5 fra AWS Lambda med Java-artiklen, en gang for hver af vores to metoder.

Lad os bruge følgende funktionsnavne:

  • StorePersonFunction til handleRequest metode (funktion 1)
  • GetPersonByHTTPParamFunction til handleGetByParam metode (funktion 2)

Vi er også nødt til at definere en miljøvariabel TABLE_NAME med værdi "Person".

4.8. Test af funktionerne

Før vi fortsætter med den aktuelle API Gateway-del, kan vi køre en hurtig test i AWS-konsollen, bare for at kontrollere, om vores Lambda-funktioner kører korrekt og kan håndtere Proxy Integration-formatet.

Test af en Lambda-funktion fra AWS-konsollen fungerer som beskrevet i AWS Lambda med Java-artiklen.

Imidlertid, når vi opretter en testbegivenhed, skal vi overveje det specielle Proxy Integration-format, som vores funktioner forventer. Vi kan enten bruge API Gateway AWS Proxy skabelon og tilpas det til vores behov, eller vi kan kopiere og indsætte følgende begivenheder:

Til StorePersonFunction, vi skal bruge dette:

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

Som tidligere omtalt, har legeme skal have typen Snor, selvom den indeholder en JSON-struktur. Årsagen er, at API Gateway sender sine anmodninger i samme format.

Følgende svar skal returneres:

{"isBase64Encoded": false, "headers": {"x-custom-header": "min tilpassede headerværdi"}, "body": "{\" meddelelse \ ": \" Nyt element oprettet \ "}", "statusCode": 200}

Her kan vi se, at legeme af vores svar er en Snor, selvom den indeholder en JSON-struktur.

Lad os se på input til GetPersonByHTTPParamFunction.

For at teste stiparameterfunktionaliteten ville indgangen se sådan ud:

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

Og inputet til afsendelse af en forespørgselsstrengparameter ville være:

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

Som et svar bør vi få følgende for begge sagsmetoder:

{"headers": {"x-custom-header": "min tilpassede header-værdi"}, "body": "{\" Person \ ": {\ n \" id \ ": 88, \ n \" navn \ ": \" John Doe \ "\ n}}", "statusCode": 200}

Igen, den legeme er en Snor.

5. Oprettelse og test af API

Efter at vi oprettede og implementerede Lambda-funktionerne i det foregående afsnit, Vi kan nu oprette den aktuelle API ved hjælp af AWS-konsollen.

Lad os se på den grundlæggende arbejdsgang:

  1. Opret en API i vores AWS-konto.
  2. Føj en ressource til ressourcehierarkiet i API'en.
  3. Opret en eller flere metoder til ressourcen.
  4. Opsæt integrationen mellem en metode og den tilhørende Lambda-funktion.

Vi gentager trin 2-4 for hver af vores to funktioner i de følgende afsnit.

5.1. Oprettelse af API

For at oprette API'en bliver vi nødt til at:

  1. Log ind på API Gateway-konsollen på //console.aws.amazon.com/apigateway
  2. Klik på "Kom godt i gang" og vælg derefter "Ny API"
  3. Indtast navnet på vores API (TestAPI) og bekræft ved at klikke på “Opret API”

Efter at have oprettet API kan vi nu oprette API-strukturen og linke den til vores Lambda-funktioner.

5.2. API-struktur til funktion 1

Følgende trin er nødvendige for vores StorePersonFunction:

  1. Vælg overordnet ressourceelement under "Ressourcer" -træet, og vælg derefter "Opret ressource" i rullemenuen "Handlinger". Derefter skal vi gøre følgende i "New Child Resource" -ruden:
    • Skriv "Personer" som et navn i indtastningsfeltet "Ressource navn"
    • Forlad standardværdien i indtastningsfeltet "Ressourcesti"
    • Vælg "Opret ressource"
  2. Vælg den netop oprettede ressource, vælg "Opret metode" i rullemenuen "Handlinger", og udfør følgende trin:
    • Vælg PUT fra rullelisten HTTP-metode, og vælg derefter fluebenikonet for at gemme valget
    • Lad "Lambda-funktion" være som integrationstype, og vælg "Brug Lambda Proxy-integration"
    • Vælg regionen fra "Lambda Region", hvor vi tidligere implementerede vores Lambda-funktioner
    • Type “StorePersonFunction” i “Lambda-funktion”
  3. Vælg "Gem" og bekræft med "OK", når du bliver bedt om "Tilføj tilladelse til Lambda-funktion"

5.3. API-struktur til funktion 2 - stiparametre

Trinene til vores hentning af styparametre er ens:

  1. Vælg /personer ressourceelement under "Ressourcer", og vælg derefter "Opret ressource" i rullemenuen "Handlinger". Derefter skal vi gøre følgende i New Child Resource-ruden:
    • Type "Person" som et navn i indtastningsfeltet "Ressourcenavn"
    • Skift inputfeltet "Ressourcesti" til “{Id}”
    • Vælg "Opret ressource"
  2. Vælg den netop oprettede ressource, vælg "Opret metode" i rullemenuen "Handlinger", og udfør følgende trin:
    • Vælg GET fra rullelisten HTTP-metode, og vælg derefter fluebenikonet for at gemme valget
    • Lad "Lambda-funktion" være som integrationstype, og vælg "Brug Lambda Proxy-integration"
    • Vælg regionen fra "Lambda Region", hvor vi tidligere implementerede vores Lambda-funktioner
    • Type “GetPersonByHTTPParamFunction” i “Lambda-funktion”
  3. Vælg "Gem" og bekræft med "OK", når du bliver bedt om "Tilføj tilladelse til Lambda-funktion"

Bemærk: det er vigtigt her at indstille parameteren "Ressourcesti" til “{Id}”, som vores GetPersonByPathParamFunction forventer, at denne parameter bliver navngivet nøjagtigt som denne.

5.4. API-struktur til funktion 2 - parametre for forespørgselsstreng

Trinene til modtagelse af forespørgselsstrengparametre er lidt forskellige, som vi behøver ikke oprette en ressource, men i stedet for at oprette en forespørgselsparameter til id parameter:

  1. Vælg / personer ressourceelement under "Ressourcer" -træet, vælg "Opret metode" i rullemenuen "Handlinger", og udfør følgende trin:
    • Vælg GET fra rullelisten HTTP-metode, og vælg derefter fluebenet for at gemme valget
    • Lad "Lambda-funktion" være som integrationstype, og vælg "Brug Lambda Proxy-integration"
    • Vælg regionen fra "Lambda Region", hvor vi tidligere implementerede vores Lambda-funktioner
    • Type “GetPersonByHTTPParamFunction” i “Lambda-funktion”.
  2. Vælg "Gem" og bekræft med "OK", når du bliver bedt om "Tilføj tilladelse til Lambda-funktion"
  3. Vælg "Method Request" til højre og udfør følgende trin:
    • Udvid listen over URL-forespørgselsparametre
    • Klik på "Tilføj forespørgselsstreng"
    • Type “Id” i navnefeltet, og vælg det fluebenikon, der skal gemmes
    • Marker afkrydsningsfeltet "Påkrævet"
    • Klik på pennesymbolet ved siden af ​​"Anmod validator" øverst i panelet, vælg "Validér forespørgselsstrengparametre og overskrifter", og vælg fluebenikonet

Bemærk: Det er vigtigt at indstille parameteren "Forespørgselsstreng" til “Id”, som vores GetPersonByHTTPParamFunction forventer, at denne parameter bliver navngivet nøjagtigt som denne.

5.5. Test af API

Vores API er nu klar, men det er ikke offentligt endnu. Før vi offentliggør det, vil vi først køre en hurtig test fra konsollen.

Til det kan vi vælge den respektive metode, der skal testes i "Ressourcer" -træet og klikke på "Test" -knappen. På den følgende skærm kan vi indtaste vores input, som vi ville sende det med en klient via HTTP.

Til StorePersonFunction, er vi nødt til at skrive følgende struktur i feltet "Request Body":

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

Til GetPersonByHTTPParamFunction med styparametre skal vi skrive 2 som en værdi i feltet "{id}" under "Sti".

Til GetPersonByHTTPParamFunction med forespørgselsstrengparametre skal vi skrive id = 2 som en værdi i feltet "{persons}" under "Forespørgselsstrenge".

5.6. Implementering af API

Indtil nu var vores API ikke offentlig og var derfor kun tilgængelig fra AWS-konsollen.

Som tidligere omtalt, når vi distribuerer en API, er vi nødt til at knytte den til et stadium, der er som et øjebliksbillede af API'et. Hvis vi omplacerer en API, kan vi enten opdatere en eksisterende fase eller oprette en ny.

Lad os se, hvordan URL-skemaet for vores API vil se ud:

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

Følgende trin er nødvendige for implementering:

  1. Vælg den bestemte API i navigationsruden "API'er"
  2. Vælg "Handlinger" i navigationsruden Ressourcer, og vælg "Implementér API" i rullemenuen "Handlinger"
  3. Vælg "[Ny scene]" i rullemenuen "Implementeringsfase", skriv "prøve" i “Stage name” og eventuelt give en beskrivelse af scenen og implementeringen
  4. Udløs implementeringen ved at vælge "Implementere"

Efter det sidste trin vil konsollen give API'ens rod-URL, for eksempel //0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test.

5.7. Påberåber sig slutpunktet

Da API'et er offentligt nu, vi kan kalde det ved hjælp af en hvilken som helst HTTP-klient, vi ønsker.

Med krøller, opkaldene ser ud 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 styparametre:

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

GetPersonByHTTPParamFunction for parametre til forespørgselsstrenge:

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

6. Konklusion

I denne artikel har vi kigget på, hvordan man gør AWS Lambda-funktioner tilgængelige som REST-slutpunkter ved hjælp af AWS API Gateway.

Vi udforskede de grundlæggende koncepter og terminologi i API Gateway, og vi lærte at integrere Lambda-funktioner ved hjælp af Lambda Proxy Integration.

Endelig så vi, hvordan vi opretter, implementerer og tester en API.

Som sædvanlig er al koden til denne artikel tilgængelig på GitHub.


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