Skip to content

Commit d8aa38b

Browse files
authored
[Example] Add APIGatewayV1 example (#569)
This PR adds an APIGateway V1 example, which differs slightly from the existing [V2 example](https://github.com/swift-server/swift-aws-lambda-runtime/tree/main/Examples/APIGateway). ### Motivation: While APIGatewayV2 has existed for a while, there are still some scenarios where V1 is preferable (see [Choose between REST APIs and HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html) for more details). This PR adds a working example for the `Api` endpoint type. ### Modifications: Sources/main.swift - Swapped APIGatewayRequestV2 and APIGatewayResponseV2 for their unversioned counterparts (aka V1). template.yaml - Changed the Events name and corresponding `Type: Api` values. - Added necessary additional properties to define a `GET` endpoint for an `Api` endpoint. Readme.md - Updated the request and response example outputs. ### Result: Now, an APIGateway and APIGatewayV1 example exist. > [!NOTE] > It is the author's opinion that this new example should technically be called `APIGateway` and the existing one should be renamed to `APIGatewayV2` to keep consistent with the request and response type naming conventions, but this is omitted from this request to be less disruptive.
1 parent 02d4830 commit d8aa38b

File tree

4 files changed

+262
-0
lines changed

4 files changed

+262
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// swift-tools-version:6.2
2+
3+
import PackageDescription
4+
5+
// needed for CI to test the local version of the library
6+
import struct Foundation.URL
7+
8+
let package = Package(
9+
name: "swift-aws-lambda-runtime-example",
10+
platforms: [.macOS(.v15)],
11+
products: [
12+
.executable(name: "APIGatewayLambda", targets: ["APIGatewayLambda"])
13+
],
14+
dependencies: [
15+
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
16+
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "2.0.0"),
17+
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"),
18+
],
19+
targets: [
20+
.executableTarget(
21+
name: "APIGatewayLambda",
22+
dependencies: [
23+
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
24+
.product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
25+
],
26+
path: "Sources"
27+
)
28+
]
29+
)
30+
31+
if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"],
32+
localDepsPath != "",
33+
let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]),
34+
v.isDirectory == true
35+
{
36+
// when we use the local runtime as deps, let's remove the dependency added above
37+
let indexToRemove = package.dependencies.firstIndex { dependency in
38+
if case .sourceControl(
39+
name: _,
40+
location: "https://github.com/swift-server/swift-aws-lambda-runtime.git",
41+
requirement: _
42+
) = dependency.kind {
43+
return true
44+
}
45+
return false
46+
}
47+
if let indexToRemove {
48+
package.dependencies.remove(at: indexToRemove)
49+
}
50+
51+
// then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..)
52+
print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)")
53+
package.dependencies += [
54+
.package(name: "swift-aws-lambda-runtime", path: localDepsPath)
55+
]
56+
}

Examples/APIGatewayV1/README.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# API Gateway
2+
3+
This is a simple example of an AWS Lambda function invoked through an Amazon API Gateway V1.
4+
5+
> [!NOTE]
6+
> 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).
7+
8+
## Code
9+
10+
The Lambda function takes all HTTP headers it receives as input and returns them as output.
11+
12+
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.
13+
14+
The handler is `(event: APIGatewayRequest, context: LambdaContext) -> APIGatewayResponse`. The function takes two arguments:
15+
- 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.
16+
- the context argument is a `Lambda Context`. It is a description of the runtime context.
17+
18+
The function must return a `APIGatewayResponse`.
19+
20+
`APIGatewayRequest` and `APIGatewayResponse` are defined in the [Swift AWS Lambda Events](https://github.com/swift-server/swift-aws-lambda-events) library.
21+
22+
## Build & Package
23+
24+
To build the package, type the following commands.
25+
26+
```bash
27+
swift build
28+
swift package archive --allow-network-connections docker
29+
```
30+
31+
If there is no error, there is a ZIP file ready to deploy.
32+
The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip`
33+
34+
## Deploy
35+
36+
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.
37+
38+
**Prerequisites** : Install the [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)
39+
40+
The example directory contains a file named `template.yaml` that describes the deployment.
41+
42+
To actually deploy your Lambda function and create the infrastructure, type the following `sam` command.
43+
44+
```bash
45+
sam deploy \
46+
--resolve-s3 \
47+
--template-file template.yaml \
48+
--stack-name APIGatewayLambda \
49+
--capabilities CAPABILITY_IAM
50+
```
51+
52+
At the end of the deployment, the script lists the API Gateway endpoint.
53+
The output is similar to this one.
54+
55+
```
56+
-----------------------------------------------------------------------------------------------------------------------------
57+
Outputs
58+
-----------------------------------------------------------------------------------------------------------------------------
59+
Key APIGatewayEndpoint
60+
Description API Gateway endpoint URL"
61+
Value https://a5q74es3k2.execute-api.us-east-1.amazonaws.com
62+
-----------------------------------------------------------------------------------------------------------------------------
63+
```
64+
65+
## Invoke your Lambda function
66+
67+
To invoke the Lambda function, use this `curl` command line.
68+
69+
```bash
70+
curl https://a5q74es3k2.execute-api.us-east-1.amazonaws.com
71+
```
72+
73+
Be sure to replace the URL with the API Gateway endpoint returned in the previous step.
74+
75+
This should print a JSON similar to
76+
77+
```bash
78+
{"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":{}}
79+
```
80+
81+
If you have `jq` installed, you can use it to pretty print the output.
82+
83+
```bash
84+
curl -s https://a5q74es3k2.execute-api.us-east-1.amazonaws.com | jq
85+
{
86+
"stageVariables": {},
87+
"queryStringParameters": {},
88+
"multiValueHeaders": {
89+
"Accept": [
90+
"*/*"
91+
],
92+
"User-Agent": [
93+
"curl/8.7.1"
94+
],
95+
"X-Forwarded-Proto": [
96+
"http"
97+
],
98+
"Host": [
99+
"localhost:3000"
100+
],
101+
"X-Forwarded-Port": [
102+
"3000"
103+
]
104+
},
105+
"pathParameters": {},
106+
"isBase64Encoded": false,
107+
"path": "/",
108+
"requestContext": {
109+
"apiId": "1234567890",
110+
"stage": "Prod",
111+
"httpMethod": "GET",
112+
"domainName": "localhost:3000",
113+
"requestId": "a9d2db08-8364-4da4-8237-8912bf8148c8",
114+
"identity": {
115+
"userAgent": "Custom User Agent String",
116+
"sourceIp": "127.0.0.1"
117+
},
118+
"resourceId": "123456",
119+
"path": "/",
120+
"resourcePath": "/",
121+
"accountId": "123456789012"
122+
},
123+
"multiValueQueryStringParameters": {},
124+
"resource": "/",
125+
"headers": {
126+
"Accept": "*/*",
127+
"X-Forwarded-Proto": "http",
128+
"X-Forwarded-Port": "3000",
129+
"Host": "localhost:3000",
130+
"User-Agent": "curl/8.7.1"
131+
},
132+
"httpMethod": "GET"
133+
}
134+
```
135+
136+
## Undeploy
137+
138+
When done testing, you can delete the infrastructure with this command.
139+
140+
```bash
141+
sam delete
142+
```
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftAWSLambdaRuntime open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import AWSLambdaEvents
16+
import AWSLambdaRuntime
17+
18+
let runtime = LambdaRuntime {
19+
(event: APIGatewayRequest, context: LambdaContext) -> APIGatewayResponse in
20+
21+
var header = HTTPHeaders()
22+
context.logger.debug("Rest API Message received")
23+
24+
header["content-type"] = "application/json"
25+
26+
// echo the request in the response
27+
return try APIGatewayResponse(statusCode: .ok, headers: header, encodableBody: event)
28+
}
29+
30+
try await runtime.run()
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: SAM Template for APIGateway Lambda Example
4+
5+
Resources:
6+
# Lambda function
7+
APIGatewayLambda:
8+
Type: AWS::Serverless::Function
9+
Properties:
10+
CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip
11+
Timeout: 60
12+
Handler: swift.bootstrap # ignored by the Swift runtime
13+
Runtime: provided.al2
14+
MemorySize: 128
15+
Architectures:
16+
- arm64
17+
Environment:
18+
Variables:
19+
# by default, AWS Lambda runtime produces no log
20+
# use `LOG_LEVEL: debug` for for lifecycle and event handling information
21+
# use `LOG_LEVEL: trace` for detailed input event information
22+
LOG_LEVEL: debug
23+
Events:
24+
RestApi:
25+
Type: Api
26+
Properties:
27+
Path: /
28+
Method: GET
29+
30+
Outputs:
31+
# print API Gateway endpoint
32+
APIGatewayEndpoint:
33+
Description: "API Gateway endpoint URL"
34+
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"

0 commit comments

Comments
 (0)