Closed RyPoints closed 1 month ago
Hello,
By default, the Lambda runtime serialize the JSON and pass it to your handler as a Request
type.
The Swift AWS Lambda Event library has many Swift implementation for standard event types.
The runtime hides the raw JSON from your code, you can only access the data by using the correct Swift struct that matches the event JSON.
If you want to use different types, here are a couple of samples
HTTPAPI :
import AWSLambdaEvents
import AWSLambdaRuntime
import Foundation
@main
struct HttpApiLambda: LambdaHandler {
init() {}
init(context: LambdaInitializationContext) async throws {
context.logger.info(
"Log Level env var : \(ProcessInfo.processInfo.environment["LOG_LEVEL"] ?? "info" )")
}
// the return value must be either APIGatewayV2Response or any Encodable struct
func handle(_ event: APIGatewayV2Request, context: AWSLambdaRuntimeCore.LambdaContext) async throws -> APIGatewayV2Response {
var header = HTTPHeaders()
do {
context.logger.debug("HTTP API Message received")
header["content-type"] = "application/json"
// echo the request in the response
let data = try JSONEncoder().encode(event)
let response = String(data: data, encoding: .utf8)
// if you want control on the status code and headers, return an APIGatewayV2Response
// otherwise, just return any Encodable struct, the runtime will wrap it for you
return APIGatewayV2Response(statusCode: .ok, headers: header, body: response)
} catch {
// should never happen as the decoding was made by the runtime
// when the input event is malformed, this function is not even called
header["content-type"] = "text/plain"
return APIGatewayV2Response(statusCode: .badRequest, headers: header, body: "\(error.localizedDescription)")
}
}
}
SQS
import AWSLambdaEvents
import AWSLambdaRuntime
import Foundation
@main
struct SQSLambda: LambdaHandler {
typealias Event = SQSEvent
typealias Output = Void
init() {}
init(context: LambdaInitializationContext) async throws {
context.logger.info(
"Log Level env var : \(ProcessInfo.processInfo.environment["LOG_LEVEL"] ?? "info" )")
}
func handle(_ event: Event, context: AWSLambdaRuntimeCore.LambdaContext) async throws -> Output {
context.logger.info("Log Level env var : \(ProcessInfo.processInfo.environment["LOG_LEVEL"] ?? "not defined" )" )
context.logger.debug("SQS Message received, with \(event.records.count) record")
for msg in event.records {
context.logger.debug("Message ID : \(msg.messageId)")
context.logger.debug("Message body : \(msg.body)")
}
}
}
Lambda URL
import AWSLambdaEvents
import AWSLambdaRuntime
import Foundation
@main
struct UrlLambda: LambdaHandler {
init() {}
init(context: LambdaInitializationContext) async throws {
context.logger.info(
"Log Level env var : \(ProcessInfo.processInfo.environment["LOG_LEVEL"] ?? "info" )")
}
// the return value must be either APIGatewayV2Response or any Encodable struct
func handle(_ event: FunctionURLRequest, context: AWSLambdaRuntimeCore.LambdaContext) async throws
-> FunctionURLResponse
{
var header = HTTPHeaders()
do {
context.logger.debug("HTTP API Message received")
header["content-type"] = "application/json"
// echo the request in the response
let data = try JSONEncoder().encode(event)
let response = String(data: data, encoding: .utf8)
// if you want control on the status code and headers, return an APIGatewayV2Response
// otherwise, just return any Encodable struct, the runtime will wrap it for you
return FunctionURLResponse(statusCode: .ok, headers: header, body: response)
} catch {
// should never happen as the decoding was made by the runtime
// when the input event is malformed, this function is not even called
header["content-type"] = "text/plain"
return FunctionURLResponse(
statusCode: .badRequest, headers: header, body: "\(error.localizedDescription)")
}
}
}
Will take a look at your samples when I have a moment. I'm looking at a V1 REST API and the Lambda Event JSON, so slightly different than the samples, but the answer might be in the samples if I review more. Was attempting to construct some very general function that worked for all scenarios at once for verification.
Hello @RyPoints
You're correct, the example I gave above is for API Gateway v2.
There is a struct
definition for API Gateway v1 also. Check this file in the Lambda events project.
If you want to access the raw byte stream and be in charge of the decoding yourself, you can do that too.
Either you use the SimpleLambdaHandler
with a String
parameter, just like in this example
https://github.com/swift-server/swift-aws-lambda-runtime/blob/main/Examples/Echo/Lambda.swift
Or you can implement a ByteBufferLambdaHandler
that gives you access to the raw byte buffer from SwiftNIO
Thanks for the additional info. I will definitely take a look at that as well. Like the dev over here. Catching up.
Expected behavior
Received from a Lambda Event JSON test. The question is about how to get the Event JSON.
It works fine from the API Gateway, but how does one get the Lambda Event JSON?
Perhaps changing the Request type will achieve this somehow, but often interfaces in other languages than Swift provide a method to both access the API Gateway Body and the Lambda Event JSON from the same Lambda handler structure.
Actual behavior
Actual behavior is Lambda events seem to have no method to access Lambda Console Event JSON.
Steps to reproduce
Log all variables when in the AWS Lambda Event JSON console and passing an event JSON. All variables are nil.
If possible, minimal yet complete reproducer code (or URL to code)
See above.
What version of this project (
swift-aws-lambda-runtime
) are you using?.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime", branch: "main"),
Swift version
5.10
Amazon Linux 2 docker image version
Amazon Linux 2 (Karoo) and now Amazon Linux 2023.4.20240401 where it's also running fine.