|
| 1 | +# Streaming Codable Lambda function |
| 2 | + |
| 3 | +This example demonstrates how to use the new `StreamingLambdaHandlerWithEvent` protocol to create Lambda functions that: |
| 4 | + |
| 5 | +1. **Receive JSON input**: Automatically decode JSON events into Swift structs |
| 6 | +2. **Stream responses**: Send data incrementally as it becomes available |
| 7 | +3. **Execute background work**: Perform additional processing after the response is sent |
| 8 | + |
| 9 | +The example uses the new streaming codable interface that combines the benefits of: |
| 10 | +- Type-safe JSON input decoding (like regular `LambdaHandler`) |
| 11 | +- Response streaming capabilities (like `StreamingLambdaHandler`) |
| 12 | +- Background work execution after response completion |
| 13 | + |
| 14 | +Streaming responses incurs a cost. For more information, see [AWS Lambda Pricing](https://aws.amazon.com/lambda/pricing/). |
| 15 | + |
| 16 | +You can stream responses through [Lambda function URLs](https://docs.aws.amazon.com/lambda/latest/dg/urls-configuration.html), the AWS SDK, or using the Lambda [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/dg/API_InvokeWithResponseStream.html) API. |
| 17 | + |
| 18 | +## Code |
| 19 | + |
| 20 | +The sample code creates a `StreamingFromEventHandler` struct that conforms to the `StreamingLambdaHandlerWithEvent` protocol provided by the Swift AWS Lambda Runtime. |
| 21 | + |
| 22 | +The `handle(...)` method of this protocol receives incoming events as a decoded Swift struct (`StreamingRequest`) and returns the output through a `LambdaResponseStreamWriter`. |
| 23 | + |
| 24 | +The Lambda function expects a JSON payload with the following structure: |
| 25 | + |
| 26 | +```json |
| 27 | +{ |
| 28 | + "count": 5, |
| 29 | + "message": "Hello from streaming Lambda!", |
| 30 | + "delayMs": 1000 |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +Where: |
| 35 | +- `count`: Number of messages to stream (1-100) |
| 36 | +- `message`: The message content to repeat |
| 37 | +- `delayMs`: Optional delay between messages in milliseconds (defaults to 500ms) |
| 38 | + |
| 39 | +The response is streamed through the `LambdaResponseStreamWriter`, which is passed as an argument in the `handle` function. The code calls the `write(_:)` function of the `LambdaResponseStreamWriter` with partial data repeatedly written before finally closing the response stream by calling `finish()`. Developers can also choose to return the entire output and not stream the response by calling `writeAndFinish(_:)`. |
| 40 | + |
| 41 | +An error is thrown if `finish()` is called multiple times or if it is called after having called `writeAndFinish(_:)`. |
| 42 | + |
| 43 | +The `handle(...)` method is marked as `mutating` to allow handlers to be implemented with a `struct`. |
| 44 | + |
| 45 | +Once the struct is created and the `handle(...)` method is defined, the sample code creates a `LambdaRuntime` struct and initializes it with the handler just created. Then, the code calls `run()` to start the interaction with the AWS Lambda control plane. |
| 46 | + |
| 47 | +Key features demonstrated: |
| 48 | +- **JSON Input Decoding**: The function automatically parses the JSON input into a `StreamingRequest` struct |
| 49 | +- **Input Validation**: Validates the count parameter and returns an error message if invalid |
| 50 | +- **Progressive Streaming**: Sends messages one by one with configurable delays |
| 51 | +- **Timestamped Output**: Each message includes an ISO8601 timestamp |
| 52 | +- **Background Processing**: Performs cleanup and logging after the response is complete |
| 53 | +- **Error Handling**: Gracefully handles invalid input with descriptive error messages |
| 54 | + |
| 55 | +## Build & Package |
| 56 | + |
| 57 | +To build & archive the package, type the following commands. |
| 58 | + |
| 59 | +```bash |
| 60 | +swift package archive --allow-network-connections docker |
| 61 | +``` |
| 62 | + |
| 63 | +If there is no error, there is a ZIP file ready to deploy. |
| 64 | +The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/StreamingFromEvent/StreamingFromEvent.zip` |
| 65 | + |
| 66 | +## Test locally |
| 67 | + |
| 68 | +You can test the function locally before deploying: |
| 69 | + |
| 70 | +```bash |
| 71 | +swift run & |
| 72 | + |
| 73 | +# In another terminal, test with curl: |
| 74 | +curl -v \ |
| 75 | + --header "Content-Type: application/json" \ |
| 76 | + --data '{"count": 3, "message": "Hello World!", "delayMs": 1000}' \ |
| 77 | + http://127.0.0.1:7000/invoke |
| 78 | +``` |
| 79 | + |
| 80 | +## Deploy with the AWS CLI |
| 81 | + |
| 82 | +Here is how to deploy using the `aws` command line. |
| 83 | + |
| 84 | +### Step 1: Create the function |
| 85 | + |
| 86 | +```bash |
| 87 | +# Replace with your AWS Account ID |
| 88 | +AWS_ACCOUNT_ID=012345678901 |
| 89 | +aws lambda create-function \ |
| 90 | +--function-name StreamingFromEvent \ |
| 91 | +--zip-file fileb://.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/StreamingFromEvent/StreamingFromEvent.zip \ |
| 92 | +--runtime provided.al2 \ |
| 93 | +--handler provided \ |
| 94 | +--architectures arm64 \ |
| 95 | +--role arn:aws:iam::${AWS_ACCOUNT_ID}:role/lambda_basic_execution |
| 96 | +``` |
| 97 | + |
| 98 | +The `--architectures` flag is only required when you build the binary on an Apple Silicon machine (Apple M1 or more recent). It defaults to `x64`. |
| 99 | + |
| 100 | +Be sure to set `AWS_ACCOUNT_ID` with your actual AWS account ID (for example: 012345678901). |
| 101 | + |
| 102 | +### Invoke your Lambda function |
| 103 | + |
| 104 | +To invoke the Lambda function, use the AWS CLI: |
| 105 | + |
| 106 | +```bash |
| 107 | +aws lambda invoke \ |
| 108 | + --function-name StreamingFromEvent \ |
| 109 | + --payload $(echo '{"count": 5, "message": "Streaming from AWS!", "delayMs": 500}' | base64) \ |
| 110 | + response.txt && cat response.txt |
| 111 | +``` |
| 112 | + |
| 113 | +This should output the following result, with configurable delays between each message: |
| 114 | + |
| 115 | +``` |
| 116 | +[2024-07-15T05:00:00Z] Message 1/3: Hello World! |
| 117 | +[2024-07-15T05:00:01Z] Message 2/3: Hello World! |
| 118 | +[2024-07-15T05:00:02Z] Message 3/3: Hello World! |
| 119 | +✅ Successfully sent 3 messages |
| 120 | +``` |
| 121 | + |
| 122 | +### Undeploy |
| 123 | + |
| 124 | +When done testing, you can delete the Lambda function with this command. |
| 125 | + |
| 126 | +```bash |
| 127 | +aws lambda delete-function --function-name StreamingFromEvent |
| 128 | +``` |
0 commit comments