-
Notifications
You must be signed in to change notification settings - Fork 118
[Example] Add APIGatewayV1 example #569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
a84ab03
9a4cf90
fab6af7
f1e7073
65e9ad1
a00ba60
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// swift-tools-version:6.2 | ||
|
||
import PackageDescription | ||
|
||
// needed for CI to test the local version of the library | ||
import struct Foundation.URL | ||
|
||
let package = Package( | ||
name: "swift-aws-lambda-runtime-example", | ||
platforms: [.macOS(.v15)], | ||
products: [ | ||
.executable(name: "APIGatewayLambda", targets: ["APIGatewayLambda"]) | ||
], | ||
dependencies: [ | ||
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below | ||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "2.0.0"), | ||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"), | ||
], | ||
targets: [ | ||
.executableTarget( | ||
name: "APIGatewayLambda", | ||
dependencies: [ | ||
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), | ||
.product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), | ||
], | ||
path: "Sources" | ||
) | ||
] | ||
) | ||
|
||
if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], | ||
localDepsPath != "", | ||
let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), | ||
v.isDirectory == true | ||
{ | ||
// when we use the local runtime as deps, let's remove the dependency added above | ||
let indexToRemove = package.dependencies.firstIndex { dependency in | ||
if case .sourceControl( | ||
name: _, | ||
location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", | ||
requirement: _ | ||
) = dependency.kind { | ||
return true | ||
} | ||
return false | ||
} | ||
if let indexToRemove { | ||
package.dependencies.remove(at: indexToRemove) | ||
} | ||
|
||
// then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) | ||
print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") | ||
package.dependencies += [ | ||
.package(name: "swift-aws-lambda-runtime", path: localDepsPath) | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
# API Gateway | ||
|
||
This is a simple example of an AWS Lambda function invoked through an Amazon API Gateway V1. | ||
|
||
> [!NOTE] | ||
> This example uses the API Gateway V1 `Api` endpoint type, whereas the [API Gateway V2](https://github.com/swift-server/swift-aws-lambda-runtime/tree/main/Examples/APIGateway) example uses the `HttpApi` endpoint type. For more information, see [Choose between REST AIs and HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html). | ||
|
||
## Code | ||
|
||
The Lambda function takes all HTTP headers it receives as input and returns them as output. | ||
|
||
The code creates a `LambdaRuntime` struct. In it's simplest form, the initializer takes a function as argument. The function is the handler that will be invoked when the API Gateway receives an HTTP request. | ||
|
||
The handler is `(event: APIGatewayRequest, context: LambdaContext) -> APIGatewayResponse`. The function takes two arguments: | ||
- the event argument is a `APIGatewayRequest`. It is the parameter passed by the API Gateway. It contains all data passed in the HTTP request and some meta data. | ||
- the context argument is a `Lambda Context`. It is a description of the runtime context. | ||
|
||
The function must return a `APIGatewayResponse`. | ||
|
||
`APIGatewayRequest` and `APIGatewayResponse` are defined in the [Swift AWS Lambda Events](https://github.com/swift-server/swift-aws-lambda-events) library. | ||
|
||
## Build & Package | ||
|
||
To build the package, type the following commands. | ||
|
||
```bash | ||
swift build | ||
swift package archive --allow-network-connections docker | ||
``` | ||
|
||
If there is no error, there is a ZIP file ready to deploy. | ||
The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip` | ||
|
||
## Deploy | ||
|
||
The deployment must include the Lambda function and the API Gateway. We use the [Serverless Application Model (SAM)](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) to deploy the infrastructure. | ||
|
||
**Prerequisites** : Install the [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) | ||
|
||
The example directory contains a file named `template.yaml` that describes the deployment. | ||
|
||
To actually deploy your Lambda function and create the infrastructure, type the following `sam` command. | ||
|
||
```bash | ||
sam deploy \ | ||
--resolve-s3 \ | ||
--template-file template.yaml \ | ||
--stack-name APIGatewayLambda \ | ||
--capabilities CAPABILITY_IAM | ||
``` | ||
|
||
At the end of the deployment, the script lists the API Gateway endpoint. | ||
The output is similar to this one. | ||
|
||
``` | ||
----------------------------------------------------------------------------------------------------------------------------- | ||
Outputs | ||
----------------------------------------------------------------------------------------------------------------------------- | ||
Key APIGatewayEndpoint | ||
Description API Gateway endpoint URL" | ||
Value https://a5q74es3k2.execute-api.us-east-1.amazonaws.com | ||
----------------------------------------------------------------------------------------------------------------------------- | ||
``` | ||
|
||
## Invoke your Lambda function | ||
|
||
To invoke the Lambda function, use this `curl` command line. | ||
|
||
```bash | ||
curl https://a5q74es3k2.execute-api.us-east-1.amazonaws.com | ||
``` | ||
|
||
Be sure to replace the URL with the API Gateway endpoint returned in the previous step. | ||
|
||
This should print a JSON similar to | ||
|
||
```bash | ||
{"httpMethod":"GET","queryStringParameters":{},"isBase64Encoded":false,"resource":"\/","path":"\/","headers":{"X-Forwarded-Port":"3000","X-Forwarded-Proto":"http","User-Agent":"curl\/8.7.1","Host":"localhost:3000","Accept":"*\/*"},"requestContext":{"resourcePath":"\/","identity":{"sourceIp":"127.0.0.1","userAgent":"Custom User Agent String"},"httpMethod":"GET","resourceId":"123456","accountId":"123456789012","apiId":"1234567890","requestId":"a9d2db08-8364-4da4-8237-8912bf8148c8","domainName":"localhost:3000","stage":"Prod","path":"\/"},"multiValueQueryStringParameters":{},"pathParameters":{},"multiValueHeaders":{"Accept":["*\/*"],"Host":["localhost:3000"],"X-Forwarded-Port":["3000"],"User-Agent":["curl\/8.7.1"],"X-Forwarded-Proto":["http"]},"stageVariables":{}} | ||
``` | ||
|
||
If you have `jq` installed, you can use it to pretty print the output. | ||
|
||
```bash | ||
curl -s https://a5q74es3k2.execute-api.us-east-1.amazonaws.com | jq | ||
{ | ||
"stageVariables": {}, | ||
"queryStringParameters": {}, | ||
"multiValueHeaders": { | ||
"Accept": [ | ||
"*/*" | ||
], | ||
"User-Agent": [ | ||
"curl/8.7.1" | ||
], | ||
"X-Forwarded-Proto": [ | ||
"http" | ||
], | ||
"Host": [ | ||
"localhost:3000" | ||
], | ||
"X-Forwarded-Port": [ | ||
"3000" | ||
] | ||
}, | ||
"pathParameters": {}, | ||
"isBase64Encoded": false, | ||
"path": "/", | ||
"requestContext": { | ||
"apiId": "1234567890", | ||
"stage": "Prod", | ||
"httpMethod": "GET", | ||
"domainName": "localhost:3000", | ||
"requestId": "a9d2db08-8364-4da4-8237-8912bf8148c8", | ||
"identity": { | ||
"userAgent": "Custom User Agent String", | ||
"sourceIp": "127.0.0.1" | ||
}, | ||
"resourceId": "123456", | ||
"path": "/", | ||
"resourcePath": "/", | ||
"accountId": "123456789012" | ||
}, | ||
"multiValueQueryStringParameters": {}, | ||
"resource": "/", | ||
"headers": { | ||
"Accept": "*/*", | ||
"X-Forwarded-Proto": "http", | ||
"X-Forwarded-Port": "3000", | ||
"Host": "localhost:3000", | ||
"User-Agent": "curl/8.7.1" | ||
}, | ||
"httpMethod": "GET" | ||
} | ||
``` | ||
|
||
## Undeploy | ||
|
||
When done testing, you can delete the infrastructure with this command. | ||
|
||
```bash | ||
sam delete | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the SwiftAWSLambdaRuntime open source project | ||
// | ||
// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors | ||
// Licensed under Apache License v2.0 | ||
// | ||
// See LICENSE.txt for license information | ||
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
import AWSLambdaEvents | ||
import AWSLambdaRuntime | ||
|
||
let runtime = LambdaRuntime { | ||
(event: APIGatewayRequest, context: LambdaContext) -> APIGatewayResponse in | ||
|
||
var header = HTTPHeaders() | ||
context.logger.debug("Rest API Message received") | ||
|
||
header["content-type"] = "application/json" | ||
|
||
// echo the request in the response | ||
return try APIGatewayResponse(statusCode: .ok, headers: header, encodableBody: event) | ||
} | ||
|
||
try await runtime.run() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
AWSTemplateFormatVersion: '2010-09-09' | ||
Transform: AWS::Serverless-2016-10-31 | ||
Description: SAM Template for APIGateway Lambda Example | ||
|
||
Resources: | ||
# Lambda function | ||
APIGatewayLambda: | ||
Type: AWS::Serverless::Function | ||
Properties: | ||
CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip | ||
Timeout: 60 | ||
Handler: swift.bootstrap # ignored by the Swift runtime | ||
Runtime: provided.al2 | ||
MemorySize: 512 | ||
|
||
Architectures: | ||
- arm64 | ||
Environment: | ||
Variables: | ||
# by default, AWS Lambda runtime produces no log | ||
# use `LOG_LEVEL: debug` for for lifecycle and event handling information | ||
# use `LOG_LEVEL: trace` for detailed input event information | ||
LOG_LEVEL: debug | ||
Events: | ||
RestApi: | ||
Type: Api | ||
Properties: | ||
Path: / | ||
Method: GET | ||
|
||
Outputs: | ||
# print API Gateway endpoint | ||
APIGatewayEndpoint: | ||
Description: "API Gateway endpoint URL" | ||
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would update this to 2025