Skip to content

Commit ba1e41a

Browse files
committed
Update quote API example
1 parent e0a9711 commit ba1e41a

File tree

10 files changed

+197
-45
lines changed

10 files changed

+197
-45
lines changed

Examples/quoteapi/.gitignore

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
/.aws-sam
2-
/.build
3-
/.swiftpm
4-
/.vscode
1+
.aws-sam
2+
.build
3+
.index-build
4+
.swiftpm
5+
.vscode
56
Package.resolved
67
samconfig.toml
78
*.d

Examples/quoteapi/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# image used to compile your Swift code
2-
FROM public.ecr.aws/docker/library/swift:5.9.1-amazonlinux2
2+
FROM public.ecr.aws/docker/library/swift:6.1-amazonlinux2
33
RUN yum -y install git jq tar zip openssl-devel

Examples/quoteapi/Makefile

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
### Add functions here and link them to builder-bot format MUST BE "build-FunctionResourceName in template.yaml"
22

33
build-QuoteService: builder-bot
4+
build-LambdaAuthorizer: builder-bot
45

56
# Helper commands
67
build:
@@ -10,16 +11,20 @@ deploy:
1011
sam deploy
1112

1213
logs:
13-
sam logs --stack-name QuoteService --name QuoteService
14+
sam logs --stack-name QuoteService
1415

1516
tail:
16-
sam logs --stack-name QuoteService --name QuoteService --tail
17+
sam logs --stack-name QuoteService --tail
1718

1819
local:
19-
LOCAL_LAMBDA_SERVER_ENABLED=true swift run QuoteService
20+
swift run QuoteService
21+
22+
local-invoke:
23+
curl -v -H 'Authorization: Bearer 123' -X POST --data @events/GetQuote.json http://127.0.0.1:7000/invoke
2024

2125
invoke:
22-
curl -v -H 'Authorization: 123' https://k3lbszo7x6.execute-api.us-east-1.amazonaws.com/stocks/AAPL
26+
## curl -v -H 'Authorization: Bearer 123' https://<REPLACE_WITH_YOUR_API_URI>/stocks/AAPL
27+
curl -v -H 'Authorization: Bearer 123' https://lq2rria2n6.execute-api.us-east-1.amazonaws.com/stocks/AAPL
2328

2429
###################### No Change required below this line ##########################
2530

@@ -30,17 +35,15 @@ builder-bot:
3035
$(eval $@ARTIFACTS_DIR = $(PWD)/.aws-sam/build/$($@PRODUCT))
3136

3237
## Building from swift-openapi-lambda in a local directory (not from Github)
33-
## 1. git clone https://github.com/swift-server/swift-openapi-lambda ..
34-
## 2. Change `Package.swift` dependency to ../swift-openapi-lambda
35-
36-
## 3. add /.. to BUILD_SRC
37-
## $(eval $@BUILD_SRC = $(PWD)/..)
38-
$(eval $@BUILD_SRC = $(PWD))
38+
## 2. Change `Package.swift` dependency to path: "../.."
3939

40-
## 4. add `cd quoteapi &&` to the docker BUILD_CMD
41-
## $(eval $@BUILD_CMD = "ls && cd quoteapi && swift build --static-swift-stdlib --product $($@PRODUCT) -c release --build-path /build-target")
40+
## 3. add /../.. to BUILD_SRC
41+
$(eval $@BUILD_SRC = $(PWD)/../..)
42+
## $(eval $@BUILD_SRC = $(PWD))
4243

43-
$(eval $@BUILD_CMD = "swift build --static-swift-stdlib --product $($@PRODUCT) -c release --build-path /build-target")
44+
## 4. add `cd Examples/quoteapi &&` to the docker BUILD_CMD
45+
$(eval $@BUILD_CMD = "ls && cd Examples/quoteapi && swift build --static-swift-stdlib --product $($@PRODUCT) -c release --build-path /build-target")
46+
## $(eval $@BUILD_CMD = "swift build --static-swift-stdlib --product $($@PRODUCT) -c release --build-path /build-target")
4447

4548
# build docker image to compile Swift for Linux
4649
docker build -f Dockerfile . -t swift-builder

Examples/quoteapi/Package.swift

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
// swift-tools-version: 5.9
1+
// swift-tools-version: 6.0
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
55

66
let package = Package(
77
name: "QuoteService",
88
platforms: [
9-
.macOS(.v13), .iOS(.v15), .tvOS(.v15), .watchOS(.v6),
9+
.macOS(.v15)
1010
],
1111
products: [
1212
.executable(name: "QuoteService", targets: ["QuoteService"])
1313
],
1414
dependencies: [
1515
.package(url: "https://github.com/apple/swift-openapi-generator.git", from: "1.4.0"),
16-
.package(url: "https://github.com/apple/swift-openapi-runtime.git", from: "1.5.0"),
17-
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha.3"),
18-
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "0.4.0"),
19-
.package(url: "https://github.com/swift-server/swift-openapi-lambda.git", from: "0.2.0"),
20-
// .package(name: "swift-openapi-lambda", path: "../swift-openapi-lambda")
16+
.package(url: "https://github.com/apple/swift-openapi-runtime.git", from: "1.8.2"),
17+
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "2.0.0-beta.1"),
18+
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.2.0"),
19+
// .package(url: "https://github.com/swift-server/swift-openapi-lambda.git", from: "0.3.0"),
20+
.package(name: "swift-openapi-lambda", path: "../.."),
2121
],
2222
targets: [
2323
.executableTarget(
@@ -28,7 +28,7 @@ let package = Package(
2828
.product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
2929
.product(name: "OpenAPILambda", package: "swift-openapi-lambda"),
3030
],
31-
path: "Sources",
31+
path: "Sources/QuoteAPI",
3232
resources: [
3333
.copy("openapi.yaml"),
3434
.copy("openapi-generator-config.yaml"),
@@ -39,6 +39,14 @@ let package = Package(
3939
package: "swift-openapi-generator"
4040
)
4141
]
42-
)
42+
),
43+
.executableTarget(
44+
name: "LambdaAuthorizer",
45+
dependencies: [
46+
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
47+
.product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
48+
],
49+
path: "Sources/LambdaAuthorizer"
50+
),
4351
]
4452
)

Examples/quoteapi/README.md

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@ The **sam deploy** command creates the Lambda function and API Gateway in your A
2828
sam deploy --guided
2929
```
3030

31-
Accept the default response to every prompt, except the following warning:
32-
33-
```bash
34-
QuoteService may not have authorization defined, Is this okay? [y/N]: y
35-
```
36-
37-
The project creates a publicly accessible API endpoint. This is a warning to inform you the API does not have authorization. If you are interested in adding authorization to the API, please refer to the [SAM Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-httpapi.html).
31+
The project creates an API endpoint protected by a bearer token authorization. Use token value '123' while testing. Youc an change the token validation logic in the `LambdaAuthorizer` function. To learn more about Lambda authorizer function, refer to [the API Gateway documentation](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html).
3832

3933
## Use the API
4034

@@ -54,7 +48,7 @@ Use cURL or a tool such as [Postman](https://www.postman.com/) to interact with
5448
**Invoke the API Endpoint**
5549

5650
```bash
57-
curl https://[your-api-endpoint]/stocks/AMZN
51+
curl -H 'Authorization: Bearer 123' https://[your-api-endpoint]/stocks/AMZN
5852
```
5953

6054
## Test the API Locally
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift OpenAPI Lambda open source project
4+
//
5+
// Copyright (c) 2023 Amazon.com, Inc. or its affiliates
6+
// and the Swift OpenAPI Lambda project authors
7+
// Licensed under Apache License v2.0
8+
//
9+
// See LICENSE.txt for license information
10+
// See CONTRIBUTORS.txt for the list of Swift OpenAPI Lambda project authors
11+
//
12+
// SPDX-License-Identifier: Apache-2.0
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
//===----------------------------------------------------------------------===//
17+
//
18+
// This source file is part of the SwiftAWSLambdaRuntime open source project
19+
//
20+
// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors
21+
// Licensed under Apache License v2.0
22+
//
23+
// See LICENSE.txt for license information
24+
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
25+
//
26+
// SPDX-License-Identifier: Apache-2.0
27+
//
28+
//===----------------------------------------------------------------------===//
29+
30+
import AWSLambdaEvents
31+
import AWSLambdaRuntime
32+
33+
//
34+
// This is an example of a policy authorizer that always authorizes the request.
35+
// The policy authorizer returns an IAM policy document that defines what the Lambda function caller can do and optional context key-value pairs
36+
//
37+
// This code is shown for the example only and is not used in this demo.
38+
// This code doesn't perform any type of token validation. It should be used as a reference only.
39+
// let policyAuthorizerHandler:
40+
// (APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws -> APIGatewayLambdaAuthorizerPolicyResponse = {
41+
// (request: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in
42+
43+
// context.logger.debug("+++ Policy Authorizer called +++")
44+
45+
// // typically, this function will check the validity of the incoming token received in the request
46+
47+
// // then it creates and returns a response
48+
// return APIGatewayLambdaAuthorizerPolicyResponse(
49+
// principalId: "John Appleseed",
50+
51+
// // this policy allows the caller to invoke any API Gateway endpoint
52+
// policyDocument: .init(statement: [
53+
// .init(
54+
// action: "execute-api:Invoke",
55+
// effect: .allow,
56+
// resource: "*"
57+
// )
58+
59+
// ]),
60+
61+
// // this is additional context we want to return to the caller
62+
// context: [
63+
// "abc1": "xyz1",
64+
// "abc2": "xyz2",
65+
// ]
66+
// )
67+
// }
68+
69+
//
70+
// This is an example of a simple authorizer that always authorizes the request.
71+
// A simple authorizer returns a yes/no decision and optional context key-value pairs
72+
//
73+
// This code doesn't perform any type of token validation. It should be used as a reference only.
74+
let simpleAuthorizerHandler:
75+
(APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws -> APIGatewayLambdaAuthorizerSimpleResponse = {
76+
(request: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in
77+
78+
context.logger.debug("+++ Simple Authorizer called +++")
79+
80+
guard let authToken = request.headers["authorization"],
81+
authToken == "Bearer 123"
82+
else {
83+
context.logger.warning("Missing or invalid Authorization header")
84+
return .init(isAuthorized: false, context: [:])
85+
}
86+
87+
return APIGatewayLambdaAuthorizerSimpleResponse(
88+
// this is the authorization decision: yes or no
89+
isAuthorized: true,
90+
91+
// this is additional context we want to return to the caller
92+
context: ["abc1": "xyz1"]
93+
)
94+
}
95+
96+
// create the runtime and start polling for new events.
97+
// in this demo we use the simple authorizer handler
98+
let runtime = LambdaRuntime(body: simpleAuthorizerHandler)
99+
try await runtime.run()

Examples/quoteapi/Sources/QuoteService.swift renamed to Examples/quoteapi/Sources/QuoteAPI/QuoteService.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import Foundation
1717
import OpenAPIRuntime
1818
import OpenAPILambda
19+
// import ServiceLifecycle
1920

2021
@main
2122
struct QuoteServiceImpl: APIProtocol, OpenAPILambdaHttpApi {
@@ -24,6 +25,32 @@ struct QuoteServiceImpl: APIProtocol, OpenAPILambdaHttpApi {
2425
try self.registerHandlers(on: transport)
2526
}
2627

28+
static func main() async throws {
29+
30+
// when you just need to run the Lambda function, call Self.run()
31+
try await Self.run()
32+
33+
// when you need to have access to the runtime for advanced usage (dependency injection, Service LifeCycle, etc)
34+
// create the LambdaRuntime and run it
35+
36+
// Here is an example with Service Lifecycle
37+
// Add the following in Package.swift
38+
// .package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.6.0"),
39+
// and
40+
// .product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
41+
// Add `import ServiceLifecycle` at the top of this file`
42+
43+
// let lambdaRuntime = try LambdaRuntime(body: Self.handler())
44+
// try await lambdaRuntime.run()
45+
// let serviceGroup = ServiceGroup(
46+
// services: [lambdaRuntime],
47+
// gracefulShutdownSignals: [.sigterm],
48+
// cancellationSignals: [.sigint],
49+
// logger: Logger(label: "ServiceGroup")
50+
// )
51+
// try await serviceGroup.run()
52+
}
53+
2754
func getQuote(_ input: Operations.getQuote.Input) async throws -> Operations.getQuote.Output {
2855

2956
let symbol = input.path.symbol
File renamed without changes.
File renamed without changes.

Examples/quoteapi/template.yml

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ Globals:
88
CodeUri: .
99
Handler: swift.bootstrap
1010
Runtime: provided.al2
11-
MemorySize: 512
11+
MemorySize: 128
1212
Architectures:
1313
- arm64
1414

1515
Resources:
16-
# Lambda function
16+
# QuoteService Lambda function
1717
QuoteService:
1818
Type: AWS::Serverless::Function
1919
Properties:
@@ -32,30 +32,50 @@ Resources:
3232
ApiId: !Ref MyProtectedApi
3333
Path: /{proxy+}
3434
Method: ANY
35-
Auth:
36-
Authorizer: MyLambdaAuthorizer
3735

3836
Metadata:
3937
BuildMethod: makefile
4038

39+
# Lambda authorizer function
40+
LambdaAuthorizer:
41+
Type: AWS::Serverless::Function
42+
Properties:
43+
Timeout: 29 # max 29 seconds for Lambda authorizers
44+
Environment:
45+
Variables:
46+
# by default, AWS Lambda runtime produces no log
47+
# use `LOG_LEVEL: debug` for for lifecycle and event handling information
48+
# use `LOG_LEVEL: trace` for detailed input event information
49+
LOG_LEVEL: trace
50+
Metadata:
51+
BuildMethod: makefile
52+
53+
# The API Gateway
4154
MyProtectedApi:
4255
Type: AWS::Serverless::HttpApi
4356
Properties:
4457
Auth:
4558
DefaultAuthorizer: MyLambdaAuthorizer
4659
Authorizers:
4760
MyLambdaAuthorizer:
48-
AuthorizerPayloadFormatVersion: 2.0
49-
EnableFunctionDefaultPermissions: true
50-
EnableSimpleResponses: true
51-
FunctionArn: arn:aws:lambda:us-east-1:486652066693:function:LambdaAuthorizer-LambdaAuthorizer-TSH4AsHiqICi
61+
FunctionArn: !GetAtt LambdaAuthorizer.Arn
5262
Identity:
5363
Headers:
54-
- Authorization
64+
- Authorization
65+
AuthorizerPayloadFormatVersion: "2.0"
66+
EnableSimpleResponses: true
67+
68+
# Give the API Gateway permissions to invoke the Lambda authorizer
69+
AuthorizerPermission:
70+
Type: AWS::Lambda::Permission
71+
Properties:
72+
Action: lambda:InvokeFunction
73+
FunctionName: !Ref LambdaAuthorizer
74+
Principal: apigateway.amazonaws.com
75+
SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${MyProtectedApi}/*
5576

5677
# print API endpoint
5778
Outputs:
5879
SwiftAPIEndpoint:
5980
Description: "API Gateway endpoint URL for your application"
6081
Value: !Sub "https://${MyProtectedApi}.execute-api.${AWS::Region}.amazonaws.com"
61-
# Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"

0 commit comments

Comments
 (0)