Skip to content

Commit 24580d4

Browse files
committed
Add quote api example code
1 parent eaaf98d commit 24580d4

File tree

10 files changed

+383
-0
lines changed

10 files changed

+383
-0
lines changed

Examples/quoteapi/.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/.aws-sam
2+
/.build
3+
/.swiftpm
4+
/.vscode
5+
Package.resolved
6+
samconfig.toml
7+
*.d
8+
*o
9+
*swiftdeps

Examples/quoteapi/Dockerfile

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

Examples/quoteapi/Makefile

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
### Add functions here and link them to builder-bot format MUST BE "build-FunctionResourceName in template.yaml"
2+
3+
build-QuoteService: builder-bot
4+
5+
# Helper commands
6+
build:
7+
sam build
8+
9+
deploy:
10+
sam deploy
11+
12+
logs:
13+
sam logs --stack-name QuoteService --name QuoteService
14+
15+
tail:
16+
sam logs --stack-name QuoteService --name QuoteService --tail
17+
18+
local:
19+
LOCAL_LAMBDA_SERVER_ENABLED=true swift run QuoteService
20+
21+
invoke:
22+
curl -v -H 'Authorization: 123' https://k3lbszo7x6.execute-api.us-east-1.amazonaws.com/stocks/AAPL
23+
24+
###################### No Change required below this line ##########################
25+
26+
builder-bot:
27+
$(eval $@PRODUCT = $(subst build-,,$(MAKECMDGOALS)))
28+
$(eval $@BUILD_DIR = $(PWD)/.aws-sam/build-swift)
29+
$(eval $@STAGE = $($@BUILD_DIR)/lambda)
30+
$(eval $@ARTIFACTS_DIR = $(PWD)/.aws-sam/build/$($@PRODUCT))
31+
32+
## 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))
39+
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")
42+
43+
$(eval $@BUILD_CMD = "swift build --static-swift-stdlib --product $($@PRODUCT) -c release --build-path /build-target")
44+
45+
# build docker image to compile Swift for Linux
46+
docker build -f Dockerfile . -t swift-builder
47+
48+
# prep directories
49+
mkdir -p $($@BUILD_DIR)/lambda $($@ARTIFACTS_DIR)
50+
51+
# compile application inside Docker image using source code from local project folder
52+
53+
docker run --rm -v $($@BUILD_DIR):/build-target -v $($@BUILD_SRC):/build-src -w /build-src swift-builder bash -cl $($@BUILD_CMD)
54+
55+
# create lambda bootstrap file
56+
docker run --rm -v $($@BUILD_DIR):/build-target -v `pwd`:/build-src -w /build-src swift-builder bash -cl "cd /build-target/lambda && ln -s $($@PRODUCT) /bootstrap"
57+
58+
# copy binary to stage
59+
cp $($@BUILD_DIR)/release/$($@PRODUCT) $($@STAGE)/bootstrap
60+
61+
# copy app from stage to artifacts dir
62+
cp $($@STAGE)/* $($@ARTIFACTS_DIR)

Examples/quoteapi/Package.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// swift-tools-version: 5.9
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "QuoteService",
8+
platforms: [
9+
.macOS(.v13), .iOS(.v15), .tvOS(.v15), .watchOS(.v6),
10+
],
11+
products: [
12+
.executable(name: "QuoteService", targets: ["QuoteService"]),
13+
],
14+
dependencies: [
15+
.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")
21+
],
22+
targets: [
23+
.executableTarget(
24+
name: "QuoteService",
25+
dependencies: [
26+
.product(name: "OpenAPIRuntime",package: "swift-openapi-runtime"),
27+
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
28+
.product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
29+
.product(name: "OpenAPILambda",package: "swift-openapi-lambda"),
30+
],
31+
path: "Sources",
32+
resources: [
33+
.copy("openapi.yaml"),
34+
.copy("openapi-generator-config.yaml")
35+
],
36+
plugins: [
37+
.plugin(
38+
name: "OpenAPIGenerator",
39+
package: "swift-openapi-generator"
40+
)
41+
]
42+
)
43+
]
44+
)

Examples/quoteapi/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# QuoteAPI
2+
3+
This application illustrates how to deploy a Server-Side Swift workload on AWS using the [AWS Serverless Application Model (SAM)](https://aws.amazon.com/serverless/sam/) toolkit. The workload is a simple REST API that returns a string from an Amazon API Gateway. Requests to the API Gateway endpoint are handled by an AWS Lambda Function written in Swift.
4+
5+
6+
## Prerequisites
7+
8+
To build this sample application, you need:
9+
10+
- [AWS Account](https://console.aws.amazon.com/)
11+
- [AWS Command Line Interface (AWS CLI)](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html) - install the CLI and [configure](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html) it with credentials to your AWS account
12+
- [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) - a command-line tool used to create serverless workloads on AWS
13+
- [Docker Desktop](https://www.docker.com/products/docker-desktop/) - to compile your Swift code for Linux deployment to AWS Lambda
14+
15+
## Build the application
16+
17+
The **sam build** command uses Docker to compile your Swift Lambda function and package it for deployment to AWS.
18+
19+
```bash
20+
sam build
21+
```
22+
23+
## Deploy the application
24+
25+
The **sam deploy** command creates the Lambda function and API Gateway in your AWS account.
26+
27+
```bash
28+
sam deploy --guided
29+
```
30+
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).
38+
39+
## Use the API
40+
41+
At the end of the deployment, SAM displays the endpoint of your API Gateway:
42+
43+
```bash
44+
Outputs
45+
----------------------------------------------------------------------------------------
46+
Key SwiftAPIEndpoint
47+
Description API Gateway endpoint URL for your application
48+
Value https://[your-api-id].execute-api.[your-aws-region].amazonaws.com
49+
----------------------------------------------------------------------------------------
50+
```
51+
52+
Use cURL or a tool such as [Postman](https://www.postman.com/) to interact with your API. Replace **[your-api-endpoint]** with the SwiftAPIEndpoint value from the deployment output.
53+
54+
**Invoke the API Endpoint**
55+
56+
```bash
57+
curl https://[your-api-endpoint]/stocks/AMZN
58+
```
59+
60+
## Test the API Locally
61+
SAM also allows you to execute your Lambda functions locally on your development computer. Follow these instructions to execute the Lambda function locally. Further capabilities can be explored in the [SAM Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-using-invoke.html).
62+
63+
**Event Files**
64+
65+
When a Lambda function is invoked, API Gateway sends an event to the function with all the data packaged with the API call. When running the functions locally, you pass in a json file to the function that simulates the event data. The **events** folder contains a json file for the function.
66+
67+
**Invoke the Lambda Function Locally**
68+
69+
```bash
70+
sam local invoke QuoteService --event events/GetQuote.json
71+
```
72+
73+
## Cleanup
74+
75+
When finished with your application, use SAM to delete it from your AWS account. Answer **Yes (y)** to all prompts. This will delete all of the application resources created in your AWS account.
76+
77+
```bash
78+
sam delete
79+
```
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import Foundation
2+
import OpenAPIRuntime
3+
import OpenAPILambda
4+
5+
@main
6+
struct QuoteServiceImpl: APIProtocol, OpenAPILambdaHttpApi {
7+
8+
init(transport: OpenAPILambdaTransport) throws {
9+
try self.registerHandlers(on: transport)
10+
}
11+
12+
func getQuote(_ input: Operations.getQuote.Input) async throws -> Operations.getQuote.Output {
13+
14+
let symbol = input.path.symbol
15+
16+
var date: Date = Date()
17+
if let dateString = input.query.date {
18+
let dateFormatter = DateFormatter()
19+
dateFormatter.dateFormat = "yyyyMMdd"
20+
date = dateFormatter.date(from: dateString) ?? Date()
21+
}
22+
23+
let price = Components.Schemas.quote(
24+
symbol: symbol,
25+
price: Double.random(in: 100..<150).rounded(),
26+
change: Double.random(in: -5..<5).rounded(),
27+
changePercent: Double.random(in: -0.05..<0.05),
28+
volume: Double.random(in: 10000..<100000).rounded(),
29+
timestamp: date)
30+
31+
return .ok(.init(body: .json(price)))
32+
}
33+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
generate:
2+
- types
3+
- server
4+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
openapi: 3.1.0
2+
info:
3+
title: StockQuoteService
4+
version: 1.0.0
5+
6+
components:
7+
schemas:
8+
quote:
9+
type: object
10+
properties:
11+
symbol:
12+
type: string
13+
price:
14+
type: number
15+
change:
16+
type: number
17+
changePercent:
18+
type: number
19+
volume:
20+
type: number
21+
timestamp:
22+
type: string
23+
format: date-time
24+
25+
paths:
26+
/stocks/{symbol}:
27+
get:
28+
summary: Get the latest quote for a stock
29+
operationId: getQuote
30+
parameters:
31+
- name: symbol
32+
in: path
33+
required: true
34+
schema:
35+
type: string
36+
- name: date
37+
in: query
38+
required: false
39+
schema:
40+
type: string
41+
format: date
42+
tags:
43+
- stocks
44+
responses:
45+
200:
46+
description: OK
47+
content:
48+
application/json:
49+
schema:
50+
$ref: '#/components/schemas/quote'
51+
400:
52+
description: Bad Request
53+
404:
54+
description: Not Found
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"rawQueryString": "",
3+
"headers": {
4+
"host": "b2k1t8fon7.execute-api.us-east-1.amazonaws.com",
5+
"x-forwarded-port": "443",
6+
"content-length": "0",
7+
"x-amzn-trace-id": "Root=1-6571d134-63dbe8ee21efa87555d59265",
8+
"x-forwarded-for": "191.95.148.219",
9+
"x-forwarded-proto": "https",
10+
"accept": "*/*",
11+
"user-agent": "curl/8.1.2"
12+
},
13+
"requestContext": {
14+
"apiId": "b2k1t8fon7",
15+
"http": {
16+
"sourceIp": "191.95.148.219",
17+
"userAgent": "curl/8.1.2",
18+
"method": "GET",
19+
"path": "/stocks/AAPL",
20+
"protocol": "HTTP/1.1"
21+
},
22+
"timeEpoch": 1701957940365,
23+
"domainPrefix": "b2k1t8fon7",
24+
"accountId": "486652066693",
25+
"time": "07/Dec/2023:14:05:40 +0000",
26+
"stage": "$default",
27+
"domainName": "b2k1t8fon7.execute-api.us-east-1.amazonaws.com",
28+
"requestId": "Pk2gOia2IAMEPOw="
29+
},
30+
"isBase64Encoded": false,
31+
"version": "2.0",
32+
"routeKey": "$default",
33+
"rawPath": "/stocks/AAPL"
34+
}

Examples/quoteapi/template.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: SAM Template for QuoteService
4+
5+
Globals:
6+
Function:
7+
Timeout: 60
8+
CodeUri: .
9+
Handler: swift.bootstrap
10+
Runtime: provided.al2
11+
MemorySize: 512
12+
Architectures:
13+
- arm64
14+
15+
Resources:
16+
# Lambda function
17+
QuoteService:
18+
Type: AWS::Serverless::Function
19+
Properties:
20+
Environment:
21+
Variables:
22+
# by default, AWS Lambda runtime produces no log
23+
# use `LOG_LEVEL: debug` for for lifecycle and event handling information
24+
# use `LOG_LEVEL: trace` for detailed input event information
25+
LOG_LEVEL: trace
26+
27+
Events:
28+
# pass through all HTTP verbs and paths
29+
Api:
30+
Type: HttpApi
31+
Properties:
32+
ApiId: !Ref MyProtectedApi
33+
Path: /{proxy+}
34+
Method: ANY
35+
Auth:
36+
Authorizer: MyLambdaAuthorizer
37+
38+
Metadata:
39+
BuildMethod: makefile
40+
41+
MyProtectedApi:
42+
Type: AWS::Serverless::HttpApi
43+
Properties:
44+
Auth:
45+
DefaultAuthorizer: MyLambdaAuthorizer
46+
Authorizers:
47+
MyLambdaAuthorizer:
48+
AuthorizerPayloadFormatVersion: 2.0
49+
EnableFunctionDefaultPermissions: true
50+
EnableSimpleResponses: true
51+
FunctionArn: arn:aws:lambda:us-east-1:486652066693:function:LambdaAuthorizer-LambdaAuthorizer-TSH4AsHiqICi
52+
Identity:
53+
Headers:
54+
- Authorization
55+
56+
# print API endpoint
57+
Outputs:
58+
SwiftAPIEndpoint:
59+
Description: "API Gateway endpoint URL for your application"
60+
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)