@@ -4,6 +4,7 @@ import com.amazonaws.services.lambda.runtime.Context
4
4
import com.amazonaws.services.lambda.runtime.RequestHandler
5
5
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
6
6
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent
7
+ import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
7
8
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
8
9
import com.github.mduesterhoeft.router.ProtoBufUtils.toJsonWithoutWrappers
9
10
import com.google.common.net.MediaType
@@ -29,16 +30,16 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
29
30
log.debug(" match result for route '$routerFunction ' is '$matchResult '" )
30
31
if (matchResult.match) {
31
32
val handler: HandlerFunction <Any , Any > = routerFunction.handler
32
- val requestBody = deserializeRequest(handler, input)
33
- val request = Request (input, requestBody, routerFunction.requestPredicate.pathPattern)
34
33
return try {
34
+ val requestBody = deserializeRequest(handler, input)
35
+ val request = Request (input, requestBody, routerFunction.requestPredicate.pathPattern)
35
36
val response = router.filter.then(handler as HandlerFunction <* , * >).invoke(request)
36
37
createResponse(input, response)
37
- } catch (e: RuntimeException ) {
38
+ } catch (e: Exception ) {
38
39
when (e) {
39
- is ApiException -> createErrorResponse (input, e)
40
+ is ApiException -> createApiExceptionErrorResponse (input, e)
40
41
.also { log.info(" Caught api error while handling ${input.httpMethod} ${input.path} - $e " ) }
41
- else -> createInternalServerErrorResponse (input, e)
42
+ else -> createUnexpectedErrorResponse (input, e)
42
43
.also { log.error(" Caught exception handling ${input.httpMethod} ${input.path} - $e " , e) }
43
44
}
44
45
}
@@ -64,7 +65,7 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
64
65
private fun handleNonDirectMatch (matchResults : List <RequestMatchResult >, input : APIGatewayProxyRequestEvent ): APIGatewayProxyResponseEvent {
65
66
// no direct match
66
67
if (matchResults.any { it.matchPath && it.matchMethod && ! it.matchContentType }) {
67
- return createErrorResponse (
68
+ return createApiExceptionErrorResponse (
68
69
input, ApiException (
69
70
httpResponseStatus = 415 ,
70
71
message = " Unsupported Media Type" ,
@@ -73,7 +74,7 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
73
74
)
74
75
}
75
76
if (matchResults.any { it.matchPath && it.matchMethod && ! it.matchAcceptType }) {
76
- return createErrorResponse (
77
+ return createApiExceptionErrorResponse (
77
78
input, ApiException (
78
79
httpResponseStatus = 406 ,
79
80
message = " Not Acceptable" ,
@@ -82,15 +83,15 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
82
83
)
83
84
}
84
85
if (matchResults.any { it.matchPath && ! it.matchMethod }) {
85
- return createErrorResponse (
86
+ return createApiExceptionErrorResponse (
86
87
input, ApiException (
87
88
httpResponseStatus = 405 ,
88
89
message = " Method Not Allowed" ,
89
90
code = " METHOD_NOT_ALLOWED"
90
91
)
91
92
)
92
93
}
93
- return createErrorResponse (
94
+ return createApiExceptionErrorResponse (
94
95
input, ApiException (
95
96
httpResponseStatus = 404 ,
96
97
message = " Not found" ,
@@ -99,7 +100,7 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
99
100
)
100
101
}
101
102
102
- open fun createErrorResponse (input : APIGatewayProxyRequestEvent , ex : ApiException ): APIGatewayProxyResponseEvent =
103
+ open fun createApiExceptionErrorResponse (input : APIGatewayProxyRequestEvent , ex : ApiException ): APIGatewayProxyResponseEvent =
103
104
APIGatewayProxyResponseEvent ()
104
105
.withBody(objectMapper.writeValueAsString(mapOf (
105
106
" message" to ex.message,
@@ -109,14 +110,28 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
109
110
.withStatusCode(ex.httpResponseStatus)
110
111
.withHeaders(mapOf (" Content-Type" to " application/json" ))
111
112
112
- open fun createInternalServerErrorResponse (input : APIGatewayProxyRequestEvent , ex : java.lang.RuntimeException ): APIGatewayProxyResponseEvent =
113
- APIGatewayProxyResponseEvent ()
114
- .withBody(objectMapper.writeValueAsString(mapOf (
115
- " message" to ex.message,
116
- " code" to " INTERNAL_SERVER_ERROR"
117
- )))
118
- .withStatusCode(500 )
119
- .withHeaders(mapOf (" Content-Type" to " application/json" ))
113
+ open fun createUnexpectedErrorResponse (input : APIGatewayProxyRequestEvent , ex : Exception ): APIGatewayProxyResponseEvent =
114
+ when (ex) {
115
+ is MissingKotlinParameterException ->
116
+ APIGatewayProxyResponseEvent ()
117
+ .withBody(objectMapper.writeValueAsString(
118
+ listOf (mapOf (
119
+ " path" to ex.parameter.name.orEmpty(),
120
+ " message" to " Missing required field" ,
121
+ " code" to " MISSING_REQUIRED_FIELDS"
122
+ ))))
123
+ .withStatusCode(422 )
124
+ .withHeaders(mapOf (" Content-Type" to " application/json" ))
125
+ else ->
126
+ APIGatewayProxyResponseEvent ()
127
+ .withBody(objectMapper.writeValueAsString(mapOf (
128
+ " message" to ex.message,
129
+ " code" to " INTERNAL_SERVER_ERROR"
130
+ )))
131
+ .withStatusCode(500 )
132
+ .withHeaders(mapOf (" Content-Type" to " application/json" ))
133
+ }
134
+
120
135
121
136
open fun <T > createResponse (input : APIGatewayProxyRequestEvent , response : ResponseEntity <T >): APIGatewayProxyResponseEvent {
122
137
val accept = MediaType .parse(input.acceptHeader())
0 commit comments