Skip to content

Commit 962d172

Browse files
ruibritoptmduesterhoeft
authored andcommitted
deserialize request body to type class when body is an array/list (#6)
* deserialize request body to type class when body is an array/list * more generic
1 parent 24c448a commit 962d172

File tree

3 files changed

+31
-7
lines changed

3 files changed

+31
-7
lines changed

src/main/kotlin/com/github/mduesterhoeft/router/APIGatewayProxyEventExtensions.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@ fun DELETE(path: String) = DELETE().withPath(path)
3232
* The port is taken from the x-forwarded-port header. Standard ports are omitted.
3333
*/
3434
fun APIGatewayProxyRequestEvent.location(path: String): URI {
35-
val host = getHeaderCaseInsensitive("host")?:"localhost"
36-
val proto = getHeaderCaseInsensitive("x-forwarded-proto")?:"http"
35+
val host = getHeaderCaseInsensitive("host") ?: "localhost"
36+
val proto = getHeaderCaseInsensitive("x-forwarded-proto") ?: "http"
3737
val portPart = getHeaderCaseInsensitive("x-forwarded-port")
3838
?.let {
3939
when {
4040
proto == "https" && it == "443" -> null
4141
proto == "http" && it == "80" -> null
4242
else -> ":$it"
4343
}
44-
}?: ""
44+
} ?: ""
4545
return URI("$proto://$host$portPart/${path.removePrefix("/")}")
4646
}
4747

src/main/kotlin/com/github/mduesterhoeft/router/RequestHandler.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.amazonaws.services.lambda.runtime.Context
44
import com.amazonaws.services.lambda.runtime.RequestHandler
55
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
66
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent
7+
import com.fasterxml.jackson.databind.type.TypeFactory
78
import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
89
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
910
import com.github.mduesterhoeft.router.ProtoBufUtils.toJsonWithoutWrappers
@@ -13,6 +14,7 @@ import org.slf4j.Logger
1314
import org.slf4j.LoggerFactory
1415
import java.util.Base64
1516
import kotlin.reflect.KClass
17+
import kotlin.reflect.full.isSubclassOf
1618
import kotlin.reflect.jvm.reflect
1719

1820
abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
@@ -55,9 +57,14 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
5557
input: APIGatewayProxyRequestEvent
5658
): Any {
5759
val requestType = handler.reflect()!!.parameters.first().type.arguments.first().type?.classifier as KClass<*>
58-
return when (requestType) {
59-
Unit::class -> Unit
60-
String::class -> input.body!!
60+
return when {
61+
requestType == Unit::class -> Unit
62+
requestType == String::class -> input.body!!
63+
requestType.isSubclassOf(Collection::class) -> {
64+
val kClass = handler.reflect()!!.parameters.first().type.arguments.first().type!!.arguments.first().type!!.classifier as KClass<*>
65+
val type = TypeFactory.defaultInstance().constructParametricType(requestType.javaObjectType, kClass.javaObjectType)
66+
objectMapper.readValue(input.body, type)
67+
}
6168
else -> objectMapper.readValue(input.body, requestType.java)
6269
}
6370
}
@@ -132,7 +139,6 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
132139
.withHeaders(mapOf("Content-Type" to "application/json"))
133140
}
134141

135-
136142
open fun <T> createResponse(input: APIGatewayProxyRequestEvent, response: ResponseEntity<T>): APIGatewayProxyResponseEvent {
137143
val accept = MediaType.parse(input.acceptHeader())
138144
return when {

src/test/kotlin/com/github/mduesterhoeft/router/RequestHandlerTest.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,22 @@ class RequestHandlerTest {
113113
assert(response.body).isEqualTo("""{"greeting":"some"}""")
114114
}
115115

116+
@Test
117+
fun `should handle request with body as a List`() {
118+
119+
val response = testRequestHandler.handleRequest(
120+
POST("/somes")
121+
.withHeaders(mapOf(
122+
"Accept" to "application/json",
123+
"Content-Type" to "application/json"
124+
))
125+
.withBody("""[{ "greeting": "some" },{ "greeting": "some1" }]""".trimMargin()), mockk()
126+
)!!
127+
128+
assert(response.statusCode).isEqualTo(200)
129+
assert(response.body).isEqualTo("""[{"greeting":"some"},{"greeting":"some1"}]""")
130+
}
131+
116132
@Test
117133
fun `should return method not allowed`() {
118134

@@ -242,6 +258,8 @@ class RequestHandlerTest {
242258
POST("/some") { r: Request<TestRequest> ->
243259
ResponseEntity.ok(TestResponse(r.body.greeting))
244260
}
261+
POST("/somes") { r: Request<List<TestRequest>> -> ResponseEntity.ok(r.body.map { TestResponse(it.greeting) }.toList())
262+
}
245263
}
246264
}
247265
}

0 commit comments

Comments
 (0)