Amazon API Gateway velmi flexibilní cloudová služba nejčastěji využívaná k tvorbě REST API poháněného lambda funkcemi. Ukážeme si jak vytvořit pomocí Serverless Frameworku jednoduchý HTTP GET endpoint, který bude vracet v odpovědi JSON.
I přes to, že následující ukázka je jednoduchá, API Gateway je velmi mocný nástroj, který umí řešit věci jako např.:
- Serverless Websockety
- Validace vstupních dat podle vlastního JSON schematu
- Generování Swagger dokumentace
- Autorizace pomocí API klíče
- Monitoring HTTP požadavků a odpovědí
- Autorizace řízená vlastní lambda funkcí
- Nastavování různých limitů a škrcení požadavků pro jednotlivé API klíče
- AWS REST API proxy (návrhový vzor pro pokročilé)
- a další...
Kompletní zdrojový kód ukázky:
Serverless.yml
V serverless.yml
souboru si nadefinujeme "customers" funkci, která bude zpracovávat API požadavky a nastavíme ji v events
tzv. "http" event source, který zajistí to, aby se funkce spustila při zavolání GET požadavku na adresu /customers
service: four-api-gateway
plugins:
- serverless-offline
provider:
name: aws
runtime: nodejs12.x
region: eu-central-1
functions:
customers:
handler: src/customers.handler
events:
- http:
path: /customers
method: get
Handler
Každá lambda funkce musí mít takzvanou “handler” funkci, která se zavolá při každém jejím spuštění. V případě Javascriptu může mít handler dvě podoby - Promise (async/await) - tak jak v našem příkladu - nebo klasický callback (více informací zde).
'use strict'
module.exports.handler = async (event) => {
console.log('Načítám klienty z databáze...')
console.log(JSON.stringify(event, null, 2))
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
customers: [
{
id: 1,
name: 'Karel'
},
{
id: 2,
name: 'Pepa'
},
{
id: 3,
name: 'Janek'
}
]
})
}
}
Struktura odpovědi
statusCode
- HTTP status kód odpovědiheaders
- HTTP hlavičky, které chceme odeslat v odpovědibody
- tělo HTTP odpovědi, které vždy musí být string - protoJSON.stringify
Příklad obsahu vstupního eventu API Gateway
{
"resource": "/customers",
"path": "/customers",
"httpMethod": "GET",
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "CZ",
"Cookie": "ajs_user_id=null",
"Host": "96g84zqz75.execute-api.eu-central-1.amazonaws.com",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"User-Agent": "......",
"Via": "2.0 7da8d24daaa6257fb28a90cd4a3bbe5d.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "cALrq-Aso-SFccHhkGlqespelPm3PnDWOFLo7NhnJk5Cx-m0jliUdg==",
"X-Amzn-Trace-Id": "Root=1-5f08d25f-3851b6fdbb7c12f7da82c599",
"X-Forwarded-For": "88.112.141.53, 130.176.34.83",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"multiValueHeaders": {
"Accept": [
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
],
"Accept-Encoding": ["gzip, deflate, br"],
"Accept-Language": ["en-GB,en-US;q=0.9,en;q=0.8"],
"CloudFront-Forwarded-Proto": ["https"],
"CloudFront-Is-Desktop-Viewer": ["true"],
"CloudFront-Is-Mobile-Viewer": ["false"],
"CloudFront-Is-SmartTV-Viewer": ["false"],
"CloudFront-Is-Tablet-Viewer": ["false"],
"CloudFront-Viewer-Country": ["CZ"],
"Cookie": ["ajs_user_id=null"],
"Host": ["96g84zqz75.execute-api.eu-central-1.amazonaws.com"],
"sec-fetch-dest": ["document"],
"sec-fetch-mode": ["navigate"],
"sec-fetch-site": ["none"],
"sec-fetch-user": ["?1"],
"upgrade-insecure-requests": ["1"],
"User-Agent": [
"......"
],
"Via": ["2.0 7da8d24baay6657fb28a90cd4a3bbe5d.cloudfront.net (CloudFront)"],
"X-Amz-Cf-Id": ["cALrq-Aso-SFtcHhkGlqespelPm5PnDWOFLo7NhnKk5Cx-m0jliUdg=="],
"X-Amzn-Trace-Id": ["Root=1-5f08d25f-1851b6fdbb7c12f7da02w199"],
"X-Forwarded-For": ["85.212.151.53, 120.876.44.13"],
"X-Forwarded-Port": ["443"],
"X-Forwarded-Proto": ["https"]
},
"queryStringParameters": null,
"multiValueQueryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"resourceId": "n0mk11",
"resourcePath": "/customers",
"httpMethod": "GET",
"extendedRequestId": "PeXO5H6DFiAFgxw=",
"requestTime": "10/Jul/2020:20:41:03 +0000",
"path": "/dev/customers",
"accountId": ".......",
"protocol": "HTTP/1.1",
"stage": "dev",
"domainPrefix": "96g8b1h47j",
"requestTimeEpoch": 1594413663007,
"requestId": "77691ybt-n351-4cde-9db7-f8b5f64e0137",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"sourceIp": "81.412.743.14",
"principalOrgId": null,
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "......",
"user": null
},
"domainName": "96g8b1h47j.execute-api.eu-central-1.amazonaws.com",
"apiId": "96g8b1h47j"
},
"body": null,
"isBase64Encoded": false
}
Lokální vývoj
serverless-offline
$ serverless offline
je populární plugin pro Serverless Framework, který umožňuje lokální vývoj REST API.
Instalace: $ npm install serverless-offline --save-dev
V ukázkovém repozitáři se lokální server spouští pomocí $ npm run dev
$ npm run dev
> 4-api-gateway@1.0.0 dev ......./4-api-gateway
> serverless offline
Serverless: Starting Offline: dev/eu-central-1.
Serverless: Routes for customers:
Serverless: GET /customers
Serverless: POST /{apiVersion}/functions/four-api-gateway-dev-customers/invocations
Serverless: Offline [HTTP] listening on http://localhost:3000
Serverless: Enter "rp" to replay the last request
Testovací požadavek na lokální API - funguje 🎉
$ curl http://localhost:3000/customers
{"customers":[{"id":1,"name":"Karel"},{"id":2,"name":"Pepa"},{"id":3,"name":"Janek"}]}
Nasazení na AWS
$ serverless deploy
V ukázkovém repozitáři se nasazení na AWS provádí pomocí příkazu:$ npm run deploy
$ npm run deploy
> 4-api-gateway@1.0.0 deploy ......./4-api-gateway
> serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service four-api-gateway.zip file to S3 (91.23 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...................................
Serverless: Stack update finished...
Service Information
service: four-api-gateway
stage: dev
region: eu-central-1
stack: four-api-gateway-dev
resources: 11
api keys:
None
endpoints:
GET - https://n7rex1gz2i.execute-api.eu-central-1.amazonaws.com/dev/customers
functions:
customers: four-api-gateway-dev-customers
layers:
None
Testovací požadavek na nasazené API - funguje 🎉
$ curl https://n7rex1gz2i.execute-api.eu-central-1.amazonaws.com/dev/customers
{"customers":[{"id":1,"name":"Karel"},{"id":2,"name":"Pepa"},{"id":3,"name":"Janek"}]}
Logy
Logy z "customers" lambdy jsou k dispozici ve službě Amazon CloudWatch v log groupě s názvem: /aws/lambda/four-api-gateway-dev-customers
Detail API v AWS konzoli
Nově vytvořené API si také můžete prohlédnout v AWS konzoli. Nicméně nedoporučoval bych tu dělat ručně jakékoliv změny, aby kvůli tomu pak nenastaly problémy se Serverless Frameworkem...
Informace o nasazené aplikaci
$ serverless info -v
Pokud budete chtít zpětně získat např. adresu "customers" endpointu, tak stačí v případě ukázkového repozitáře spustit $ npm run info
$ npm run info
> 4-api-gateway@1.0.0 info ......./4-api-gateway
> serverless info -v
Service Information
service: four-api-gateway
stage: dev
region: eu-central-1
stack: four-api-gateway-dev
resources: 11
api keys:
None
endpoints:
GET - https://n7rex1gz2i.execute-api.eu-central-1.amazonaws.com/dev/customers
functions:
customers: four-api-gateway-dev-customers
layers:
None
Stack Outputs
CustomersLambdaFunctionQualifiedArn: arn:aws:lambda:eu-central-1:124515691641:function:four-api-gateway-dev-customers:3
ServiceEndpoint: https://n7rex1gz2i.execute-api.eu-central-1.amazonaws.com/dev
ServerlessDeploymentBucketName: four-api-gateway-dev-serverlessdeploymentbucket-1ujue1xbdlkvw
Smazání z AWS
$ serverless remove
V ukázkovém repozitáři se smazání z AWS provádí pomocí příkazu:$ npm run remove
$ npm run remove
> 4-api-gateway@1.0.0 remove ......./4-api-gateway
> serverless remove
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
...........
Serverless: Stack removal finished...
Testovací požadavek na smazané API - nefunguje 🚫 👍
$ curl https://n7rex1gz2i.execute-api.eu-central-1.amazonaws.com/dev/customers
curl: (6) Could not resolve host: n7rex1gz2i.execute-api.eu-central-1.amazonaws.com
Závěr
Jak jsem již v úvodu zmínil, API Gateway je velmi mocný nástroj a v budoucnu o něm ještě pár článků na našem blogu určitě uvidíte.
V případě jakýchkoliv otázek mě neváhejte kontaktovat na Twitteru @FilipPyrek.
With ❤️ made in Brno.