Skip to content

Commit

Permalink
[RFC] Drop event label from handle methods in LambdaHandlers (#225)
Browse files Browse the repository at this point in the history
* Drop event label from handle method in LambdaHandlers
* Rename `In` to `Event` and `Out` to `Output` in `EventLoopLambdaHandler`
  • Loading branch information
fabianfett authored Sep 22, 2021
1 parent dbd675d commit e5aa488
Show file tree
Hide file tree
Showing 17 changed files with 120 additions and 120 deletions.
6 changes: 3 additions & 3 deletions Examples/LambdaFunctions/Sources/Benchmark/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import NIO
Lambda.run { $0.eventLoop.makeSucceededFuture(BenchmarkHandler()) }

struct BenchmarkHandler: EventLoopLambdaHandler {
typealias In = String
typealias Out = String
typealias Event = String
typealias Output = String

func handle(event: String, context: Lambda.Context) -> EventLoopFuture<String> {
func handle(_ event: String, context: Lambda.Context) -> EventLoopFuture<String> {
context.eventLoop.makeSucceededFuture("hello, world!")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import Logging

@main
struct CurrencyExchangeHandler: LambdaHandler {
typealias In = Request
typealias Out = [Exchange]
typealias Event = Request
typealias Output = [Exchange]

let calculator: ExchangeRatesCalculator

Expand All @@ -35,7 +35,7 @@ struct CurrencyExchangeHandler: LambdaHandler {
self.calculator = ExchangeRatesCalculator()
}

func handle(event: Request, context: Lambda.Context) async throws -> [Exchange] {
func handle(_ event: Request, context: Lambda.Context) async throws -> [Exchange] {
try await withCheckedThrowingContinuation { continuation in
self.calculator.run(logger: context.logger) { result in
switch result {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import AWSLambdaRuntime

@main
struct ErrorsHappenHandler: LambdaHandler {
typealias In = Request
typealias Out = Response
typealias Event = Request
typealias Output = Response

init(context: Lambda.InitializationContext) async throws {}

func handle(event request: Request, context: Lambda.Context) async throws -> Response {
func handle(_ request: Request, context: Lambda.Context) async throws -> Response {
// switch over the error type "requested" by the request, and trigger such error accordingly
switch request.error {
// no error here!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ import AWSLambdaRuntime
// introductory example, the obligatory "hello, world!"
@main
struct HelloWorldHandler: LambdaHandler {
typealias In = String
typealias Out = String
typealias Event = String
typealias Output = String

init(context: Lambda.InitializationContext) async throws {
// setup your resources that you want to reuse here.
}

func handle(event: String, context: Lambda.Context) async throws -> String {
func handle(_ event: String, context: Lambda.Context) async throws -> String {
"hello, world"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import Shared
// a local server simulator which will allow local debugging
@main
struct MyLambdaHandler: LambdaHandler {
typealias In = Request
typealias Out = Response
typealias Event = Request
typealias Output = Response

init(context: Lambda.InitializationContext) async throws {
// setup your resources that you want to reuse for every invocation here.
}

func handle(event request: Request, context: Lambda.Context) async throws -> Response {
func handle(_ request: Request, context: Lambda.Context) async throws -> Response {
// TODO: something useful
Response(message: "Hello, \(request.name)!")
}
Expand Down
22 changes: 11 additions & 11 deletions Sources/AWSLambdaRuntime/Lambda+Codable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,33 @@ import NIOFoundationCompat

// MARK: - Codable support

/// Implementation of a`ByteBuffer` to `In` decoding
extension EventLoopLambdaHandler where In: Decodable {
/// Implementation of a`ByteBuffer` to `Event` decoding
extension EventLoopLambdaHandler where Event: Decodable {
@inlinable
public func decode(buffer: ByteBuffer) throws -> In {
try self.decoder.decode(In.self, from: buffer)
public func decode(buffer: ByteBuffer) throws -> Event {
try self.decoder.decode(Event.self, from: buffer)
}
}

/// Implementation of `Out` to `ByteBuffer` encoding
extension EventLoopLambdaHandler where Out: Encodable {
/// Implementation of `Output` to `ByteBuffer` encoding
extension EventLoopLambdaHandler where Output: Encodable {
@inlinable
public func encode(allocator: ByteBufferAllocator, value: Out) throws -> ByteBuffer? {
public func encode(allocator: ByteBufferAllocator, value: Output) throws -> ByteBuffer? {
try self.encoder.encode(value, using: allocator)
}
}

/// Default `ByteBuffer` to `In` decoder using Foundation's JSONDecoder
/// Default `ByteBuffer` to `Event` decoder using Foundation's JSONDecoder
/// Advanced users that want to inject their own codec can do it by overriding these functions.
extension EventLoopLambdaHandler where In: Decodable {
extension EventLoopLambdaHandler where Event: Decodable {
public var decoder: LambdaCodableDecoder {
Lambda.defaultJSONDecoder
}
}

/// Default `Out` to `ByteBuffer` encoder using Foundation's JSONEncoder
/// Default `Output` to `ByteBuffer` encoder using Foundation's JSONEncoder
/// Advanced users that want to inject their own codec can do it by overriding these functions.
extension EventLoopLambdaHandler where Out: Encodable {
extension EventLoopLambdaHandler where Output: Encodable {
public var encoder: LambdaCodableEncoder {
Lambda.defaultJSONEncoder
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/AWSLambdaRuntimeCore/Lambda+String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
import NIOCore

extension EventLoopLambdaHandler where In == String {
extension EventLoopLambdaHandler where Event == String {
/// Implementation of a `ByteBuffer` to `String` decoding
@inlinable
public func decode(buffer: ByteBuffer) throws -> String {
Expand All @@ -25,7 +25,7 @@ extension EventLoopLambdaHandler where In == String {
}
}

extension EventLoopLambdaHandler where Out == String {
extension EventLoopLambdaHandler where Output == String {
/// Implementation of `String` to `ByteBuffer` encoding
@inlinable
public func encode(allocator: ByteBufferAllocator, value: String) throws -> ByteBuffer? {
Expand Down
52 changes: 26 additions & 26 deletions Sources/AWSLambdaRuntimeCore/LambdaHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import NIOCore
// MARK: - LambdaHandler

#if compiler(>=5.5)
/// Strongly typed, processing protocol for a Lambda that takes a user defined `In` and returns a user defined `Out` async.
/// Strongly typed, processing protocol for a Lambda that takes a user defined `Event` and returns a user defined `Output` async.
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
public protocol LambdaHandler: EventLoopLambdaHandler {
/// The Lambda initialization method
Expand All @@ -34,19 +34,19 @@ public protocol LambdaHandler: EventLoopLambdaHandler {
/// Concrete Lambda handlers implement this method to provide the Lambda functionality.
///
/// - parameters:
/// - event: Event of type `In` representing the event or request.
/// - event: Event of type `Event` representing the event or request.
/// - context: Runtime `Context`.
///
/// - Returns: A Lambda result ot type `Out`.
func handle(event: In, context: Lambda.Context) async throws -> Out
/// - Returns: A Lambda result ot type `Output`.
func handle(_ event: Event, context: Lambda.Context) async throws -> Output
}

@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension LambdaHandler {
public func handle(event: In, context: Lambda.Context) -> EventLoopFuture<Out> {
let promise = context.eventLoop.makePromise(of: Out.self)
public func handle(_ event: Event, context: Lambda.Context) -> EventLoopFuture<Output> {
let promise = context.eventLoop.makePromise(of: Output.self)
promise.completeWithTask {
try await self.handle(event: event, context: context)
try await self.handle(event, context: context)
}
return promise.futureResult
}
Expand All @@ -62,59 +62,59 @@ extension LambdaHandler {

// MARK: - EventLoopLambdaHandler

/// Strongly typed, `EventLoopFuture` based processing protocol for a Lambda that takes a user defined `In` and returns a user defined `Out` asynchronously.
/// `EventLoopLambdaHandler` extends `ByteBufferLambdaHandler`, performing `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer` encoding.
/// Strongly typed, `EventLoopFuture` based processing protocol for a Lambda that takes a user defined `Event` and returns a user defined `Output` asynchronously.
/// `EventLoopLambdaHandler` extends `ByteBufferLambdaHandler`, performing `ByteBuffer` -> `Event` decoding and `Output` -> `ByteBuffer` encoding.
///
/// - note: To implement a Lambda, implement either `LambdaHandler` or the `EventLoopLambdaHandler` protocol.
/// The `LambdaHandler` will offload the Lambda execution to a `DispatchQueue` making processing safer but slower
/// The `EventLoopLambdaHandler` will execute the Lambda on the same `EventLoop` as the core runtime engine, making the processing faster but requires
/// more care from the implementation to never block the `EventLoop`.
public protocol EventLoopLambdaHandler: ByteBufferLambdaHandler {
associatedtype In
associatedtype Out
associatedtype Event
associatedtype Output

/// The Lambda handling method
/// Concrete Lambda handlers implement this method to provide the Lambda functionality.
///
/// - parameters:
/// - context: Runtime `Context`.
/// - event: Event of type `In` representing the event or request.
/// - event: Event of type `Event` representing the event or request.
///
/// - Returns: An `EventLoopFuture` to report the result of the Lambda back to the runtime engine.
/// The `EventLoopFuture` should be completed with either a response of type `Out` or an `Error`
func handle(event: In, context: Lambda.Context) -> EventLoopFuture<Out>
/// The `EventLoopFuture` should be completed with either a response of type `Output` or an `Error`
func handle(_ event: Event, context: Lambda.Context) -> EventLoopFuture<Output>

/// Encode a response of type `Out` to `ByteBuffer`
/// Encode a response of type `Output` to `ByteBuffer`
/// Concrete Lambda handlers implement this method to provide coding functionality.
/// - parameters:
/// - allocator: A `ByteBufferAllocator` to help allocate the `ByteBuffer`.
/// - value: Response of type `Out`.
/// - value: Response of type `Output`.
///
/// - Returns: A `ByteBuffer` with the encoded version of the `value`.
func encode(allocator: ByteBufferAllocator, value: Out) throws -> ByteBuffer?
func encode(allocator: ByteBufferAllocator, value: Output) throws -> ByteBuffer?

/// Decode a`ByteBuffer` to a request or event of type `In`
/// Decode a`ByteBuffer` to a request or event of type `Event`
/// Concrete Lambda handlers implement this method to provide coding functionality.
///
/// - parameters:
/// - buffer: The `ByteBuffer` to decode.
///
/// - Returns: A request or event of type `In`.
func decode(buffer: ByteBuffer) throws -> In
/// - Returns: A request or event of type `Event`.
func decode(buffer: ByteBuffer) throws -> Event
}

extension EventLoopLambdaHandler {
/// Driver for `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer` encoding
/// Driver for `ByteBuffer` -> `Event` decoding and `Output` -> `ByteBuffer` encoding
@inlinable
public func handle(event: ByteBuffer, context: Lambda.Context) -> EventLoopFuture<ByteBuffer?> {
let input: In
public func handle(_ event: ByteBuffer, context: Lambda.Context) -> EventLoopFuture<ByteBuffer?> {
let input: Event
do {
input = try self.decode(buffer: event)
} catch {
return context.eventLoop.makeFailedFuture(CodecError.requestDecoding(error))
}

return self.handle(event: input, context: context).flatMapThrowing { output in
return self.handle(input, context: context).flatMapThrowing { output in
do {
return try self.encode(allocator: context.allocator, value: output)
} catch {
Expand All @@ -125,7 +125,7 @@ extension EventLoopLambdaHandler {
}

/// Implementation of `ByteBuffer` to `Void` decoding
extension EventLoopLambdaHandler where Out == Void {
extension EventLoopLambdaHandler where Output == Void {
@inlinable
public func encode(allocator: ByteBufferAllocator, value: Void) throws -> ByteBuffer? {
nil
Expand All @@ -148,7 +148,7 @@ public protocol ByteBufferLambdaHandler {
///
/// - Returns: An `EventLoopFuture` to report the result of the Lambda back to the runtime engine.
/// The `EventLoopFuture` should be completed with either a response encoded as `ByteBuffer` or an `Error`
func handle(event: ByteBuffer, context: Lambda.Context) -> EventLoopFuture<ByteBuffer?>
func handle(_ event: ByteBuffer, context: Lambda.Context) -> EventLoopFuture<ByteBuffer?>

/// Clean up the Lambda resources asynchronously.
/// Concrete Lambda handlers implement this method to shutdown resources like `HTTPClient`s and database connections.
Expand Down
4 changes: 2 additions & 2 deletions Sources/AWSLambdaRuntimeCore/LambdaRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ extension Lambda {
self.isGettingNextInvocation = true
return self.runtimeClient.getNextInvocation(logger: logger).peekError { error in
logger.error("could not fetch work from lambda runtime engine: \(error)")
}.flatMap { invocation, event in
}.flatMap { invocation, bytes in
// 2. send invocation to handler
self.isGettingNextInvocation = false
let context = Context(logger: logger,
eventLoop: self.eventLoop,
allocator: self.allocator,
invocation: invocation)
logger.debug("sending invocation to lambda handler \(handler)")
return handler.handle(event: event, context: context)
return handler.handle(bytes, context: context)
// Hopping back to "our" EventLoop is important in case the handler returns a future that
// originiated from a foreign EventLoop/EventLoopGroup.
// This can happen if the handler uses a library (lets say a DB client) that manages its own threads/loops
Expand Down
6 changes: 3 additions & 3 deletions Sources/AWSLambdaTesting/Lambda+Testing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ extension Lambda {

public static func test<Handler: LambdaHandler>(
_ handlerType: Handler.Type,
with event: Handler.In,
with event: Handler.Event,
using config: TestConfig = .init()
) throws -> Handler.Out {
) throws -> Handler.Output {
let logger = Logger(label: "test")
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer {
Expand Down Expand Up @@ -97,7 +97,7 @@ extension Lambda {
let handler = try promise.futureResult.wait()

return try eventLoop.flatSubmit {
handler.handle(event: event, context: context)
handler.handle(event, context: context)
}.wait()
}
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/CodableSample/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ struct Response: Codable {
// in this example we are receiving and responding with codables. Request and Response above are examples of how to use
// codables to model your reqeuest and response objects
struct Handler: EventLoopLambdaHandler {
typealias In = Request
typealias Out = Response
typealias Event = Request
typealias Output = Response

func handle(event: Request, context: Lambda.Context) -> EventLoopFuture<Response> {
func handle(_ event: Request, context: Lambda.Context) -> EventLoopFuture<Response> {
// as an example, respond with the input event's reversed body
context.eventLoop.makeSucceededFuture(Response(body: String(event.body.reversed())))
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/StringSample/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import NIOCore

// in this example we are receiving and responding with strings
struct Handler: EventLoopLambdaHandler {
typealias In = String
typealias Out = String
typealias Event = String
typealias Output = String

func handle(event: String, context: Lambda.Context) -> EventLoopFuture<String> {
func handle(_ event: String, context: Lambda.Context) -> EventLoopFuture<String> {
// as an example, respond with the event's reversed body
context.eventLoop.makeSucceededFuture(String(event.reversed()))
}
Expand Down
Loading

0 comments on commit e5aa488

Please sign in to comment.