Skip to content

[core] Add user-facing API for Streaming Lambda functions that receive JSON events #532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

sebsto
Copy link
Contributor

@sebsto sebsto commented Jul 15, 2025

Add user-facing API for Streaming Lambda functions that receives JSON events

Motivation:

Streaming Lambda functions developed by developers had no choice but to implement a handler that receives incoming data as a ByteBuffer. While this is useful for low-level development, I assume most developers will want to receive a JSON event to trigger their streaming Lambda function.

Going efficiently from a ByteBuffer to a Swift struct requires some code implemented in the JSON+ByteBuffer.swift file of the librray. We propose to further help developers by providing them with a new handler() function that directly receives their Decodable type.

Modifications:

This PR adds a public facing API (+ unit test + updated README) allowing developers to write a handler method accepting any Decodable struct as input.

import AWSLambdaRuntime
import NIOCore

// Define your input event structure
struct StreamingRequest: Decodable {
    let count: Int
    let message: String
    let delayMs: Int?
}

// Use the new streaming handler with JSON decoding
let runtime = LambdaRuntime { (event: StreamingRequest, responseWriter, context: LambdaContext) in
    context.logger.info("Received request to send \(event.count) messages")
    
    // Stream the messages
    for i in 1...event.count {
        let response = "Message \(i)/\(event.count): \(event.message)\n"
        try await responseWriter.write(ByteBuffer(string: response))
        
        // Optional delay between messages
        if let delay = event.delayMs, delay > 0 {
            try await Task.sleep(for: .milliseconds(delay))
        }
    }
    
    // Finish the stream
    try await responseWriter.finish()
    
    // Optional: Execute background work after response is sent
    context.logger.info("Background work: processing completed")
}

try await runtime.run()

This interface provides:

  • Type-safe JSON input: Automatic decoding of JSON events into Swift structs
  • Streaming responses: Full control over when and how to stream data back to clients
  • Background work support: Ability to execute code after the response stream is finished
  • Familiar API: Uses the same closure-based pattern as regular Lambda handlers

Because streaming Lambda functions can be invoked either directly through the API or through Lambda Function URL, this PR adds the decoding logic to support both types, shielding developers from working with Function URL requests and base64 encoding.

We understand these choice will have an impact on the raw performance for event handling. Those advanced users that want to get the maximum might use the existing handler(_ event: ByteBuffer, writer: LambaStreamingWriter) function to implement their own custom decoding logic.

This PR provides a balance between ease of use for 80% of the users vs ultimate performance, without closing the door for the 20% who need it.

Result:

Lambda function developers can now use arbitrary Decodable Swift struct or Lambda events to trigger their streaming functions. 🎉

@sebsto sebsto requested review from adam-fowler and Copilot July 15, 2025 09:16
@sebsto sebsto added the 🆕 semver/minor Adds new public API. label Jul 15, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Adds a new JSON-decoded streaming API for Swift AWS Lambda functions, including protocol definitions, adapters, tests, and documentation updates.

  • Introduce StreamingLambdaHandlerWithEvent, StreamingLambdaCodableAdapter, and a closure-based handler to accept Decodable inputs.
  • Provide unit tests covering decoding, streaming, error handling, and background-work scenarios.
  • Update root README, add a fully functional StreamingFromEvent example with SAM template, sample event, example code, and CI workflow updates.

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
readme.md Added “Lambda Streaming Response with JSON Input” section
Sources/AWSLambdaRuntime/LambdaStreaming+Codable.swift New handler protocol, JSON adapter, and LambdaRuntime inits
Tests/AWSLambdaRuntimeTests/LambdaStreamingCodableTests.swift Unit tests for streaming-codable handler and adapter
Examples/StreamingFromEvent/template.yaml SAM template for the new example
Examples/StreamingFromEvent/events/sample-request.json Sample JSON event for the example
Examples/StreamingFromEvent/Sources/main.swift Example usage of the JSON-streaming API
Examples/StreamingFromEvent/README.md Documentation for the new StreamingFromEvent example
Examples/StreamingFromEvent/Package.swift Package manifest for the example
Examples/README.md Added StreamingFromEvent to the examples index
.github/workflows/pull_request.yml Include StreamingFromEvent in CI example runs
Comments suppressed due to low confidence (5)

Examples/StreamingFromEvent/template.yaml:7

  • The logical resource ID StreamingNumbers doesn’t match the example folder name. Consider renaming it to something like StreamingFromEventFunction for consistency.
  StreamingNumbers:

Examples/StreamingFromEvent/template.yaml:10

  • The CodeUri path references StreamingNumbers but should point to the StreamingFromEvent build output (e.g. .../StreamingFromEvent/StreamingFromEvent.zip).
      CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/StreamingNumbers/StreamingNumbers.zip

Examples/StreamingFromEvent/README.md:20

  • There is no StreamingFromEventHandler struct in the example. Update this line to reference the actual closure-based handler or correct handler type used in main.swift.
The sample code creates a `StreamingFromEventHandler` struct that conforms to the `StreamingLambdaHandlerWithEvent` protocol provided by the Swift AWS Lambda Runtime.

Tests/AWSLambdaRuntimeTests/LambdaStreamingCodableTests.swift:5

  • The header uses 2024 but new code files use 2025. Update the copyright year to 2025 for consistency.
// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors

readme.md:305

  • [nitpick] Consider renaming the link text to 'StreamingFromEvent example README file' to align with the directory name and avoid confusion.
You can learn how to deploy and invoke this function in [the streaming codable example README file](Examples/StreamingFromEvent/README.md).

@sebsto sebsto marked this pull request as draft July 15, 2025 10:50
@sebsto sebsto marked this pull request as ready for review July 15, 2025 15:41
@sebsto sebsto changed the title Add user-facing API for Streaming Lambda functions that receives JSON events [core] Add user-facing API for Streaming Lambda functions that receives JSON events Jul 15, 2025
@sebsto sebsto changed the title [core] Add user-facing API for Streaming Lambda functions that receives JSON events [core] Add user-facing API for Streaming Lambda functions that receive JSON events Jul 15, 2025
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.

1 participant