An AWS Lambda Transport for Swift OpenAPI generator
This library allows to expose server side Swift OpenAPI implementation generated by the Swift OpenAPI generator as an AWS Lambda function and an AWS API Gateway.
To write and deploy AWS Lambda functions based on an OpenAPI API definition, you need the following:
- an AWS Account
- the AWS Command Line Interface (AWS CLI) - install the CLI and configure it with credentials to your AWS account
- the AWS SAM CLI - a command-line tool used to create serverless workloads on AWS
- the Docker Desktop - to compile your Swift code for Linux deployment to AWS Lambda
- Create a Swift executable project
mkdir quoteapi && cd quoteapi swift package init --name quoteapi --type executable- Write or import an OpenAI API definition in YAML or JSON
cat << EOF > Sources/openapi.yaml openapi: 3.1.0 info: title: StockQuoteService version: 1.0.0 components: schemas: quote: type: object properties: symbol: type: string price: type: number change: type: number changePercent: type: number volume: type: number timestamp: type: string format: date-time paths: /stocks/{symbol}: get: summary: Get the latest quote for a stock operationId: getQuote parameters: - name: symbol in: path required: true schema: type: string tags: - stocks responses: 200: description: OK content: application/json: schema: $ref: '#/components/schemas/quote' 400: description: Bad Request 404: description: Not Found EOF - Add a Swift OpenAPI generator configuration file to generate only the server side
cat << EOF > Sources/openapi-generator-config.yaml generate: - types - server EOF - Use this
Package.swiftfile to define targets and their dependencies
cat << EOF > Package.swift // swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "QuoteService", platforms: [ .macOS(.v13), .iOS(.v15), .tvOS(.v15), .watchOS(.v6), ], products: [ .executable(name: "QuoteService", targets: ["QuoteService"]), ], dependencies: [ .package(url: "https://github.com/apple/swift-openapi-generator.git", .upToNextMinor(from: "1.0.0-alpha.1")), .package(url: "https://github.com/apple/swift-openapi-runtime.git", .upToNextMinor(from: "1.0.0")), .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "1.0.0-alpha.1"), .package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", branch: "main"), .package(path: "../swift-openapi-lambda") ], targets: [ .executableTarget( name: "QuoteService", dependencies: [ .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), .product(name: "OpenAPIRuntime",package: "swift-openapi-runtime"), .product(name: "OpenAPILambda",package: "swift-openapi-lambda"), ], path: "Sources", resources: [ .copy("openapi.yaml"), .copy("openapi-generator-config.yaml") ], plugins: [ .plugin( name: "OpenAPIGenerator", package: "swift-openapi-generator" ) ] ), ] ) EOF- Generate server side Swift stub of the OpenAPI API definition
swift build- Replace
main.swiftwith your own implementation
rm Sources/main.swift cat << EOF > Sources/QuoteService.swift import Foundation import OpenAPIRuntime struct QuoteServiceImpl: APIProtocol { func getQuote(_ input: Operations.getQuote.Input) async throws -> Operations.getQuote.Output { let symbol = input.path.symbol // in real life, don't use random values 🤣 let price = Components.Schemas.quote( symbol: symbol, price: Double.random(in: 100..<150).rounded(), change: Double.random(in: -5..<5).rounded(), changePercent: Double.random(in: -0.05..<0.05), volume: Double.random(in: 10000..<100000).rounded(), timestamp: Date()) return .ok(.init(body: .json(price))) } } EOF- Add a Lambda function that consumes your OpenAPI service implementation. The Lambda is invoked by an AWS API Gateway.
cat << EOF > Sources/Lambda.swift mport AWSLambdaEvents import OpenAPILambda @main struct QuoteServiceLambda: OpenAPILambda { typealias Event = APIGatewayV2Request typealias Output = APIGatewayV2Response public init(transport: LambdaOpenAPITransport) throws { let openAPIHandler = QuoteServiceImpl() try openAPIHandler.registerHandlers(on: transport) } }- Add the build instructions as a Docker file and a Makefile. We build for Swift 5.9 on Amazon Linux 2
cat << EOF > Dockerfile # image used to compile your Swift code FROM public.ecr.aws/docker/library/swift:5.9.1-amazonlinux2 RUN yum -y install git jq tar zip openssl-devel EOF cat << EOF > Makefile ### Add functions here and link them to builder-bot format MUST BE "build-FunctionResourceName in template.yaml" build-QuoteService: builder-bot # Helper commands deploy: sam deploy logs: sam logs --stack-name QuoteService --name QuoteService tail: sam logs --stack-name QuoteService --name QuoteService --tail ###################### No Change required below this line ########################## builder-bot: $(eval $@PRODUCT = $(subst build-,,$(MAKECMDGOALS))) $(eval $@BUILD_DIR = $(PWD)/.aws-sam/build-swift) $(eval $@STAGE = $($@BUILD_DIR)/lambda) $(eval $@ARTIFACTS_DIR = $(PWD)/.aws-sam/build/$($@PRODUCT)) # build docker image to compile Swift for Linux docker build -f Dockerfile . -t swift-builder # prep directories mkdir -p $($@BUILD_DIR)/lambda $($@ARTIFACTS_DIR) # compile application inside Docker image using source code from local project folder docker run --rm -v $($@BUILD_DIR):/build-target -v `pwd`:/build-src -w /build-src swift-builder bash -cl "swift build --static-swift-stdlib --product $($@PRODUCT) -c release --build-path /build-target" # create lambda bootstrap file 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" # copy binary to stage cp $($@BUILD_DIR)/release/$($@PRODUCT) $($@STAGE)/bootstrap # copy app from stage to artifacts dir cp $($@STAGE)/* $($@ARTIFACTS_DIR) EOF- Build the executable
sam buildTo get started with the Swift OpenAPI generator, check out the full documentation, which contains a step-by-step tutorial.
The Swift Runtime for AWS Lambda allows you to write AWS Lambda functions in the Swift programming language.
To get started, check out this step-by-step tutorial and the documentation.