Skip to content

Conversation

natanrolnik
Copy link
Contributor

Add convenience initializer for LambdaRuntime to accept LambdaHandler instances directly

Motivation:

When using the Swift AWS Lambda Runtime with custom handler types that conform to LambdaHandler, developers previously had two options to initialize LambdaRuntime:

  1. Manually wrap their handler with LambdaCodableAdapter and LambdaHandlerAdapter:

    let lambdaHandler = MyHandler()
    let handler = LambdaCodableAdapter(
        encoder: JSONEncoder(),
        decoder: JSONDecoder(),
        handler: LambdaHandlerAdapter(handler: lambdaHandler)
    )
    let runtime = LambdaRuntime(handler: handler)
  2. Use a closure-based initializer that indirectly calls the handler:

    let lambdaHandler = MyHandler()
    let runtime = LambdaRuntime { event, context in
        try await lambdaHandler.handle(event, context: context)
    }

Both approaches are verbose and don't provide a clean, ergonomic API for the common case of initializing LambdaRuntime with a custom LambdaHandler instance. The closure approach also creates an unnecessary indirection layer, wrapping the handler in a ClosureHandler before adapting it, or using LambdaCodableAdapter.

Modifications:

Added a new convenience initializer to LambdaRuntime in Lambda+JSON.swift that accepts a LambdaHandler instance directly:

public convenience init<Event: Decodable, Output, LHandler: LambdaHandler>(
    decoder: JSONDecoder = JSONDecoder(),
    encoder: JSONEncoder = JSONEncoder(),
    logger: Logger = Logger(label: "LambdaRuntime"),
    lambdaHandler: sending LHandler
)
where
    Handler == LambdaCodableAdapter<
        LambdaHandlerAdapter<Event, Output, LHandler>,
        Event,
        Output,
        LambdaJSONEventDecoder,
        LambdaJSONOutputEncoder<Output>
    >,
    LHandler.Event == Event,
    LHandler.Output == Output

This initializer handles the wrapping of the LambdaHandler with the necessary adapters internally, matching the pattern already established for closure-based handlers.

Result:

Developers can now initialize LambdaRuntime with a LambdaHandler instance using a clean, direct API:

let lambdaHandler = MyHandler()
let runtime = LambdaRuntime(lambdaHandler: lambdaHandler)

This provides:

  • Better ergonomics: More intuitive and less verbose API
  • Consistency: Matches the pattern of accepting handlers directly, similar to how StreamingLambdaHandler can be used
  • No extra indirection: Avoids wrapping the handler in an unnecessary ClosureHandler or LambdaCodableAdapter
  • Type safety: Maintains full type inference for Event and Output types from the handler

@sebsto sebsto self-assigned this Oct 9, 2025
@sebsto sebsto added the 🆕 semver/minor Adds new public API. label Oct 9, 2025
@sebsto sebsto self-requested a review October 9, 2025 10:35
@sebsto
Copy link
Contributor

sebsto commented Oct 9, 2025

Love the idea and the simplification. Thank you @natanrolnik

@fabianfett any objection from an API point of view ?

@natanrolnik natanrolnik force-pushed the codable-handler-init branch from 56b4711 to ace567a Compare October 9, 2025 10:42
Copy link
Member

@fabianfett fabianfett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it!

Copy link
Contributor

@sebsto sebsto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A very welcome addition

@sebsto sebsto merged commit 461c18a into swift-server:main Oct 9, 2025
75 of 76 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🆕 semver/minor Adds new public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants