Adrian Witaszak
03/14/2024, 8:19 PMAPIGatewayV2HTTPEvent
in the FnHandler
but getting Reflection errorAdrian Witaszak
03/14/2024, 8:19 PMfun EventFnHandler() = FnHandler { e: APIGatewayV2HTTPEvent, _: Context ->
println(e.toString())
e.toString()
}
Adrian Witaszak
03/14/2024, 8:22 PM{
"errorMessage": "Kotlin reflection implementation is not found at runtime. Make sure you have kotlin-reflect.jar in the classpath",
"errorType": "kotlin.jvm.KotlinReflectionNotSupportedError",
"stackTrace": [
"kotlin.jvm.internal.ClassReference.error(ClassReference.kt:88)",
"kotlin.jvm.internal.ClassReference.isAbstract(ClassReference.kt:62)",
"com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory.create(KotlinJsonAdapter.kt:215)",
"com.squareup.moshi.Moshi.adapter(Moshi.java:146)",
"com.squareup.moshi.Moshi.adapter(Moshi.java:106)",
"com.squareup.moshi.Moshi.adapter(Moshi.java:80)",
"org.http4k.format.ConfigurableMoshi.adapterFor(ConfigurableMoshi.kt:94)",
"org.http4k.format.ConfigurableMoshi.asA(ConfigurableMoshi.kt:98)",
"org.http4k.serverless.AutoMarshallingFnLoader.invoke$lambda$0(AutoMarshallingFnLoader.kt:19)",
"org.http4k.serverless.AwsLambdaEventFunction.handleRequest(AwsLambdaEventFunction.kt:15)"
]
}
Adrian Witaszak
03/14/2024, 8:23 PMFnFunction
?Adrian Witaszak
03/14/2024, 8:30 PMFnHandler
?dave
03/14/2024, 8:31 PMAdrian Witaszak
03/14/2024, 8:32 PMApiGatewayV2LambdaFunction
?dave
03/14/2024, 8:32 PMdave
03/14/2024, 8:32 PMdave
03/14/2024, 8:32 PMAdrian Witaszak
03/14/2024, 9:02 PM@KotshiJsonAdapterFactory
private object LambdaJsonAdapterFactory : JsonAdapter.Factory by LambdaJsonAdapterFactory
internal val moshi = ConfigurableMoshi(
Moshi.Builder()
.add(LambdaJsonAdapterFactory)
.add(ListAdapter)
.add(MapAdapter)
.asConfigurable()
.withStandardMappings()
.done()
)
@JsonSerializable
data class Event(val message: String) {
companion object {
val lens = moshi.autoBody<Event>().toLens()
val sample = Event(message = "Hello, world!")
}
}
val eventLens = moshi.autoBody<Event>().toLens()
internal object GetHello : AppLoader {
override fun invoke(env: Map<String, String>): HttpHandler = { request ->
val event = eventLens(request)
.asResultOr { return@asResultOr Response(Status.BAD_REQUEST).body("Invalid request") }
.mapFailure { Response(Status.BAD_REQUEST).with(lens of sample) }
.map { it.message }
.get()
Response(Status.OK).body(event.toString())
}
}
@Suppress("unused")
class Handler : ApiGatewayV2LambdaFunction(GetHello)
but aws still have an issue with it:
{
"errorMessage": "method is invalid",
"errorType": "java.lang.IllegalStateException",
"stackTrace": [
"org.http4k.serverless.ApiGatewayV2AwsHttpAdapter.toHttp4kRequest(ApiGatewayV2.kt:48)",
"org.http4k.serverless.ApiGatewayV2AwsHttpAdapter.invoke(ApiGatewayV2.kt:58)",
"org.http4k.serverless.ApiGatewayV2AwsHttpAdapter.invoke(ApiGatewayV2.kt:45)",
"org.http4k.serverless.ApiGatewayFnLoader.invoke$lambda$0(ApiGatewayFnLoader.kt:24)",
"org.http4k.serverless.AwsLambdaEventFunction.handleRequest(AwsLambdaEventFunction.kt:15)"
]
}
dave
03/14/2024, 9:03 PMAdrian Witaszak
03/14/2024, 9:04 PMdave
03/14/2024, 9:05 PMAdrian Witaszak
03/14/2024, 9:06 PMdave
03/14/2024, 9:06 PMconst lambdaIntegration = new aws.apigatewayv2.Integration("hello-http4k-api-lambda-integration", {
apiId: api.id,
integrationType: "AWS_PROXY",
integrationUri: lambdaFunction.arn,
payloadFormatVersion: "2.0"
});
dave
03/14/2024, 9:06 PMdave
03/14/2024, 9:06 PMAdrian Witaszak
03/14/2024, 9:42 PMCaused by: java.lang.NullPointerException: Cannot invoke "LambdaJsonAdapterFactory.create(java.lang.reflect.Type, java.util.Set, com.squareup.moshi.Moshi)" because "this.$$delegate_0" is null
at LambdaJsonAdapterFactory.create(Handler.kt)
Adrian Witaszak
03/14/2024, 10:10 PMAdrian Witaszak
03/14/2024, 10:15 PM{
"errorMessage": "method is invalid",
"errorType": "java.lang.IllegalStateException",
"stackTrace": [
"org.http4k.serverless.ApiGatewayV2AwsHttpAdapter.toHttp4kRequest(ApiGatewayV2.kt:48)",
"org.http4k.serverless.ApiGatewayV2AwsHttpAdapter.invoke(ApiGatewayV2.kt:58)",
"org.http4k.serverless.ApiGatewayV2AwsHttpAdapter.invoke(ApiGatewayV2.kt:45)",
"org.http4k.serverless.ApiGatewayFnLoader.invoke$lambda$0(ApiGatewayFnLoader.kt:24)",
"org.http4k.serverless.AwsLambdaEventFunction.handleRequest(AwsLambdaEventFunction.kt:15)"
]
}
but i leave it for tomorrow, it is getting late.Adrian Witaszak
03/15/2024, 9:02 AMdave
03/15/2024, 9:03 AMdave
03/15/2024, 9:04 AMdave
03/15/2024, 9:05 AMAdrian Witaszak
03/15/2024, 9:15 AMdave
03/15/2024, 9:56 AMdave
03/15/2024, 9:56 AMKrisztian Balla
03/15/2024, 10:35 AMdave
03/15/2024, 10:38 AMKrisztian Balla
03/15/2024, 11:39 AMfun apig-event -> apig-response
• routing happens on the apig level so lambdas themselves are really lean only wrapping a single use case
• almost all microservices (a bunch of lambdas triggered by either apig / sqs / other aws events) are deployed inside a vpc hence using the restapi (v1 apig) but lambdas expected to be triggered that way are normalised so the events are the same in the v2 format (multivalue headers etc...)
What is the recommended way to go at it using http4k in your opinion?dave
03/15/2024, 11:43 AMdave
03/15/2024, 11:44 AMdave
03/15/2024, 11:45 AMdave
03/15/2024, 11:46 AMKrisztian Balla
03/15/2024, 11:47 AMdave
03/15/2024, 11:50 AMKrisztian Balla
03/15/2024, 11:51 AMdave
03/15/2024, 11:51 AMdave
03/15/2024, 11:52 AMdave
03/15/2024, 11:52 AMKrisztian Balla
03/15/2024, 11:53 AMdave
03/15/2024, 11:53 AMKrisztian Balla
03/15/2024, 11:53 AMdave
03/15/2024, 11:55 AMdave
03/15/2024, 11:56 AMKrisztian Balla
03/15/2024, 12:01 PMAndrew O'Hara
03/15/2024, 2:48 PMmoshi-kotlin
isn't good enough. You need to replace the kotlin module with a generated kotshi
adapter to eliminate kotlin-reflect
. If you're interested, code and slides linked below. Raw data is at the end of the slides.
https://github.com/oharaandrew314/have-your-serverless-kotlin-functionsKrisztian Balla
03/15/2024, 2:56 PMrequestContext.authorizer
using a http4k Request?
We managed to make the AppLoader
inside ApiGatewayV1LambdaFunction
approach work but it looks like a lot of the event information including the authorizer
is lost along the way.dave
03/15/2024, 3:02 PMKrisztian Balla
03/15/2024, 4:27 PMAppLoaderWithContexts
in the code I don't seem to find anything related to mapping of event.requestContext
to it.
However managed to make it work this way:
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent
import org.http4k.base64Decoded
import org.http4k.serverless.AwsLambdaEventFunction
import org.http4k.serverless.FnHandler
import org.http4k.serverless.FnLoader
fun eventFnHandler() = FnHandler { event: APIGatewayProxyRequestEvent, _: Context ->
val b = if (event.isBase64Encoded) event.body.base64Decoded() else event.body
APIGatewayProxyResponseEvent().apply {
statusCode=201
body=b
isBase64Encoded=false
}
}
fun eventFnLoader() = FnLoader { _: Map<String, String> -> eventFnHandler() }
@Suppress("unused")
class Handler : AwsLambdaEventFunction(eventFnLoader())
dave
03/15/2024, 4:41 PMcom.amazonaws.services.lambda.runtime
.,dave
03/15/2024, 4:41 PMobject Foo : ApiGatewayV2LambdaFunction(AppLoaderWithContexts { env, context ->
val key = RequestContextKey.required<Map<String, Any>>(context, LAMBDA_REQUEST_KEY)
({ req: Request ->
val context = key[req]
Response(Status.OK)
})
})
dave
03/15/2024, 4:41 PMKrisztian Balla
03/15/2024, 5:23 PMjava.lang.ClassCastException: class org.http4k.core.MemoryRequest cannot be cast to class java.util.Map (org.http4k.core.MemoryRequest is in unnamed module of loader com.amazonaws.services.lambda.runtime.api.client.CustomerClassLoader @4dd8dc3; java.util.Map is in module java.base of loader 'bootstrap')
at Handler$1$1.invoke(Handler.kt:48)
at Handler$1$1.invoke(Handler.kt:47)
at org.http4k.serverless.CommonKt$AddLambdaContextAndRequest$1$1.invoke(common.kt:14)
at org.http4k.serverless.CommonKt$AddLambdaContextAndRequest$1$1.invoke(common.kt:11)
at org.http4k.filter.ServerFilters$InitialiseRequestContext$invoke$1$1.invoke(ServerFilters.kt:375)
at org.http4k.filter.ServerFilters$InitialiseRequestContext$invoke$1$1.invoke(ServerFilters.kt:372)
at org.http4k.filter.ServerFilters$CatchAll$invoke$2$1.invoke(ServerFilters.kt:314)
at org.http4k.filter.ServerFilters$CatchAll$invoke$2$1.invoke(ServerFilters.kt:312)
at org.http4k.serverless.ApiGatewayFnLoader.invoke$lambda$0(ApiGatewayFnLoader.kt:27)
at org.http4k.serverless.AwsLambdaEventFunction.handleRequest(AwsLambdaEventFunction.kt:15)
at com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$2.call(EventHandlerLoader.java:905)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:245)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:197)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.main(AWSLambda.java:187)
dave
03/15/2024, 6:14 PM