Skip to content

Commit ddf82b3

Browse files
authored
Lambda runtime v2 (#42)
* New lambda structure similar to server * Comments, deleted commented code * Use APIGatewayV2 * Add LambdaRuntimeService * Add LambdaRuntimeService * Remove logger from LambdaRuntimeService * update comment * Require swift 6 * Use cancellable lambda runtime * Fix up runtime for latest changes * Update README * Add LambdaFunction.beforeLambdaStarts() * Use lambda runtime v2 beta * Remove Foundation imports
1 parent 48091d0 commit ddf82b3

22 files changed

+584
-515
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
timeout-minutes: 15
2020
strategy:
2121
matrix:
22-
image: ["swift:5.10", "swift:6.0", "swift:6.1", "swiftlang/swift:nightly-6.2-noble"]
22+
image: ["swift:6.0", "swift:6.1", "swiftlang/swift:nightly-6.2-noble"]
2323
container:
2424
image: ${{ matrix.image }}
2525
steps:

Package.swift

Lines changed: 5 additions & 5 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

33
import PackageDescription
44

55
let package = Package(
66
name: "hummingbird-lambda",
77
platforms: [
8-
.macOS(.v14)
8+
.macOS(.v15)
99
],
1010
products: [
1111
.library(name: "HummingbirdLambda", targets: ["HummingbirdLambda"]),
1212
.library(name: "HummingbirdLambdaTesting", targets: ["HummingbirdLambdaTesting"]),
1313
.executable(name: "HBLambdaTest", targets: ["HBLambdaTest"]),
1414
],
1515
dependencies: [
16-
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha.2"),
16+
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "2.0.0-beta"),
1717
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"),
1818
.package(url: "https://github.com/swift-extras/swift-extras-base64.git", from: "1.0.0"),
19-
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0"),
20-
.package(url: "https://github.com/apple/swift-nio.git", from: "2.32.0"),
19+
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.9.0"),
20+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"),
2121
],
2222
targets: [
2323
.target(

README.md

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,15 @@ Run Hummingbird inside an AWS Lambda
44

55
## Usage
66

7-
Create struct conforming to `LambdaFunction`. Setup your application in the `init` function: add your middleware, add route handlers etc
8-
97
```swift
10-
@main
11-
struct MyHandler: LambdaFunction {
12-
// define input and output
13-
typealias Event = APIGatewayRequest
14-
typealias Output = APIGatewayResponse
15-
typealias Context = BasicLambdaRequestContext<APIGatewayRequest>
16-
17-
init(_ app: Application) {
18-
app.middleware.add(LogRequestsMiddleware(.debug))
19-
app.router.get("hello") { _, _ in
20-
return "Hello"
21-
}
22-
}
8+
typealias AppRequestContext = BasicLambdaRequestContext<APIGatewayV2Request>
9+
10+
// Create router and add a single route returning "Hello" in its body
11+
let router = Router(context: AppRequestContext.self)
12+
router.get("hello") { _, _ in
13+
return "Hello"
2314
}
15+
// create lambda using router and run
16+
let lambda = APIGatewayV2LambdaFunction(router: router)
17+
try await lambda.runService()
2418
```
25-
26-
The `Event` and `Output` types define your input and output objects. If you are using an `APIGateway` REST interface to invoke your Lambda then set these to `APIGatewayRequest` and `APIGatewayResponse` respectively. If you are using an `APIGateway` HTML interface then set these to `APIGatewayV2Request` and `APIGatewayV2Response`. If you are using any other `Event`/`Output` types you will need to implement the `request(context:application:from:)` and `output(from:)` methods yourself.

Sources/HBLambdaTest/maths.swift

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import Hummingbird
1818
import HummingbirdLambda
1919
import Logging
2020

21+
typealias AppRequestContext = BasicLambdaRequestContext<APIGatewayV2Request>
22+
2123
struct DebugMiddleware: RouterMiddleware {
22-
typealias Context = MathsHandler.Context
24+
typealias Context = AppRequestContext
2325
func handle(
2426
_ request: Request,
2527
context: Context,
@@ -32,42 +34,34 @@ struct DebugMiddleware: RouterMiddleware {
3234
}
3335
}
3436

35-
@main
36-
struct MathsHandler: APIGatewayLambdaFunction {
37-
typealias Context = BasicLambdaRequestContext<APIGatewayRequest>
38-
39-
struct Operands: Decodable {
40-
let lhs: Double
41-
let rhs: Double
42-
}
43-
44-
struct Result: ResponseEncodable {
45-
let result: Double
46-
}
47-
48-
init(context: LambdaInitializationContext) {}
37+
struct Operands: Decodable {
38+
let lhs: Double
39+
let rhs: Double
40+
}
4941

50-
func buildResponder() -> some HTTPResponder<Context> {
51-
let router = Router(context: Context.self)
52-
router.middlewares.add(DebugMiddleware())
53-
router.post("add") { request, context -> Result in
54-
let operands = try await request.decode(as: Operands.self, context: context)
55-
return Result(result: operands.lhs + operands.rhs)
56-
}
57-
router.post("subtract") { request, context -> Result in
58-
let operands = try await request.decode(as: Operands.self, context: context)
59-
return Result(result: operands.lhs - operands.rhs)
60-
}
61-
router.post("multiply") { request, context -> Result in
62-
let operands = try await request.decode(as: Operands.self, context: context)
63-
return Result(result: operands.lhs * operands.rhs)
64-
}
65-
router.post("divide") { request, context -> Result in
66-
let operands = try await request.decode(as: Operands.self, context: context)
67-
return Result(result: operands.lhs / operands.rhs)
68-
}
69-
return router.buildResponder()
70-
}
42+
struct Result: ResponseEncodable {
43+
let result: Double
44+
}
7145

72-
func shutdown() async throws {}
46+
let router = Router(context: AppRequestContext.self)
47+
router.middlewares.add(DebugMiddleware())
48+
router.post("add") { request, context -> Result in
49+
let operands = try await request.decode(as: Operands.self, context: context)
50+
return Result(result: operands.lhs + operands.rhs)
51+
}
52+
router.post("subtract") { request, context -> Result in
53+
let operands = try await request.decode(as: Operands.self, context: context)
54+
return Result(result: operands.lhs - operands.rhs)
55+
}
56+
router.post("multiply") { request, context -> Result in
57+
let operands = try await request.decode(as: Operands.self, context: context)
58+
return Result(result: operands.lhs * operands.rhs)
59+
}
60+
router.post("divide") { request, context -> Result in
61+
let operands = try await request.decode(as: Operands.self, context: context)
62+
return Result(result: operands.lhs / operands.rhs)
7363
}
64+
let lambda = APIGatewayV2LambdaFunction(
65+
router: router
66+
)
67+
try await lambda.runService()

Sources/HummingbirdLambda/APIGatewayLambda.swift

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,13 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import AWSLambdaEvents
16-
import AWSLambdaRuntimeCore
1716
import Hummingbird
1817
import NIOCore
1918
import NIOHTTP1
2019

21-
/// Protocol for Hummingbird Lambdas that use APIGateway
22-
///
23-
/// With this protocol you no longer need to set the `Event` and `Output`
24-
/// associated values.
25-
/// ```swift
26-
/// struct MyLambda: APIGatewayLambda {
27-
/// typealias Context = MyLambdaRequestContext
28-
///
29-
/// init(context: LambdaInitializationContext) {}
30-
///
31-
/// /// build responder that will create a response from a request
32-
/// func buildResponder() -> some Responder<Context> {
33-
/// let router = Router(context: Context.self)
34-
/// router.get("hello") { _,_ in
35-
/// "Hello"
36-
/// }
37-
/// return router.buildResponder()
38-
/// }
39-
/// }
40-
/// ```
41-
public protocol APIGatewayLambdaFunction: LambdaFunction where Event == APIGatewayRequest, Output == APIGatewayResponse {
42-
associatedtype Context = BasicLambdaRequestContext<APIGatewayRequest>
43-
}
44-
45-
extension LambdaFunction where Event == APIGatewayRequest {
46-
/// Specialization of Lambda.request where `Event` is `APIGatewayRequest`
47-
public func request(context: LambdaContext, from: Event) throws -> Request {
48-
try Request(context: context, from: from)
49-
}
50-
}
51-
52-
extension LambdaFunction where Output == APIGatewayResponse {
53-
/// Specialization of Lambda.request where `Output` is `APIGatewayResponse`
54-
public func output(from response: Response) async throws -> Output {
55-
try await response.apiResponse()
56-
}
57-
}
20+
/// Typealias for Lambda function triggered by APIGateway
21+
public typealias APIGatewayLambdaFunction<Responder: HTTPResponder> = LambdaFunction<Responder, APIGatewayRequest, APIGatewayResponse>
22+
where Responder.Context: InitializableFromSource<LambdaRequestContextSource<APIGatewayRequest>>
5823

5924
// conform `APIGatewayRequest` to `APIRequest` so we can use Request.init(context:application:from)
6025
extension APIGatewayRequest: APIRequest {

Sources/HummingbirdLambda/APIGatewayV2Lambda.swift

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,13 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import AWSLambdaEvents
16-
import AWSLambdaRuntimeCore
1716
import Hummingbird
1817
import NIOCore
1918
import NIOHTTP1
2019

21-
/// Protocol for Hummingbird Lambdas that use APIGatewayV2
22-
///
23-
/// With this protocol you no longer need to set the `Event` and `Output`
24-
/// associated values.
25-
/// ```swift
26-
/// struct MyLambda: APIGatewayLambda {
27-
/// typealias Context = MyLambdaRequestContext
28-
///
29-
/// init(context: LambdaInitializationContext) {}
30-
///
31-
/// /// build responder that will create a response from a request
32-
/// func buildResponder() -> some Responder<Context> {
33-
/// let router = Router(context: Context.self)
34-
/// router.get("hello") { _,_ in
35-
/// "Hello"
36-
/// }
37-
/// return router.buildResponder()
38-
/// }
39-
/// }
40-
/// ```
41-
public protocol APIGatewayV2LambdaFunction: LambdaFunction where Event == APIGatewayV2Request, Output == APIGatewayV2Response {
42-
associatedtype Context = BasicLambdaRequestContext<APIGatewayV2Request>
43-
}
44-
45-
extension LambdaFunction where Event == APIGatewayV2Request {
46-
/// Specialization of Lambda.request where `Event` is `APIGatewayV2Request`
47-
public func request(context: LambdaContext, from: Event) throws -> Request {
48-
try Request(context: context, from: from)
49-
}
50-
}
51-
52-
extension LambdaFunction where Output == APIGatewayV2Response {
53-
/// Specialization of Lambda.request where `Output` is `APIGatewayV2Response`
54-
public func output(from response: Response) async throws -> Output {
55-
try await response.apiResponse()
56-
}
57-
}
20+
/// Typealias for Lambda function triggered by APIGatewayV2
21+
public typealias APIGatewayV2LambdaFunction<Responder: HTTPResponder> = LambdaFunction<Responder, APIGatewayV2Request, APIGatewayV2Response>
22+
where Responder.Context: InitializableFromSource<LambdaRequestContextSource<APIGatewayV2Request>>
5823

5924
// conform `APIGatewayV2Request` to `APIRequest` so we can use Request.init(context:application:from)
6025
extension APIGatewayV2Request: APIRequest {

Sources/HummingbirdLambda/BasicLambdaRequestContext.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
import AWSLambdaRuntimeCore
16-
import Foundation
1715
import Hummingbird
1816
import Logging
1917
import NIOCore

Sources/HummingbirdLambda/Deprecations.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,8 @@
1616
// temporarily to ease transition from the old symbols that included the "HB"
1717
// prefix to the new ones.
1818

19-
@_documentation(visibility: internal) @available(*, unavailable, renamed: "LambdaFunction")
20-
public typealias HBLambda = LambdaFunction
21-
@_documentation(visibility: internal) @available(*, unavailable, renamed: "APIGatewayLambdaFunction")
22-
public typealias HBAPIGatewayLambda = APIGatewayLambdaFunction
23-
@_documentation(visibility: internal) @available(*, unavailable, renamed: "APIGatewayV2LambdaFunction")
24-
public typealias HBAPIGatewayV2Lambda = APIGatewayV2LambdaFunction
19+
@_documentation(visibility: internal) @available(*, unavailable, renamed: "LambdaFunctionProtocol")
20+
public typealias HBLambda = LambdaFunctionProtocol
2521
@_documentation(visibility: internal) @available(*, unavailable, renamed: "LambdaRequestContext")
2622
public typealias HBLambdaRequestContext = LambdaRequestContext
2723
@_documentation(visibility: internal) @available(*, unavailable, renamed: "BasicLambdaRequestContext")

0 commit comments

Comments
 (0)