Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package io.moia.router.proto

import com.google.protobuf.GeneratedMessageV3
import io.moia.router.ResponseEntity
import io.moia.router.SerializationHandler
import com.google.common.net.MediaType
import com.google.protobuf.GeneratedMessageV3
import org.apache.http.entity.ContentType
import java.util.Base64

class ProtoSerializationHandler : SerializationHandler {

private val json = MediaType.parse("application/json")
private val json = ContentType.parse("application/json")

override fun supports(acceptHeader: MediaType, response: ResponseEntity<*>): Boolean =
override fun supports(acceptHeader: ContentType, response: ResponseEntity<*>): Boolean =
response.body is GeneratedMessageV3

override fun serialize(acceptHeader: MediaType, response: ResponseEntity<*>): String {
override fun serialize(acceptHeader: ContentType, response: ResponseEntity<*>): String {
val message = response.body as GeneratedMessageV3
return if (acceptHeader.`is`(json)) {
return if (json.mimeType == acceptHeader.mimeType) {
ProtoBufUtils.toJsonWithoutWrappers(message)
} else {
Base64.getEncoder().encodeToString(message.toByteArray())
Expand Down
2 changes: 1 addition & 1 deletion router/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dependencies {
compile("org.slf4j:slf4j-api:1.7.26")
compile("com.fasterxml.jackson.core:jackson-databind:2.9.8")
compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8")
compile("com.google.guava:guava:23.0")
compile("org.apache.httpcomponents:httpcore:4.4.11")

testImplementation("org.junit.jupiter:junit-jupiter-engine:5.4.0")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.4.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package io.moia.router
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.type.TypeFactory
import com.google.common.net.MediaType
import org.apache.http.entity.ContentType
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.full.isSubclassOf
Expand All @@ -25,12 +25,12 @@ class DeserializationHandlerChain(private val handlers: List<DeserializationHand
handlers.firstOrNull { it.supports(input) }?.deserialize(input, target)
}

class JsonDeserializationHandler(val objectMapper: ObjectMapper) : DeserializationHandler {
class JsonDeserializationHandler(private val objectMapper: ObjectMapper) : DeserializationHandler {

private val json = MediaType.parse("application/json")
private val json = ContentType.parse("application/json")

override fun supports(input: APIGatewayProxyRequestEvent) =
input.contentType() != null && MediaType.parse(input.contentType()).`is`(json)
input.contentType() != null && ContentType.parse(input.contentType()).mimeType == json.mimeType

override fun deserialize(input: APIGatewayProxyRequestEvent, target: KType?): Any? {
val targetClass = target?.classifier as KClass<*>
Expand Down
4 changes: 2 additions & 2 deletions router/src/main/kotlin/io/moia/router/RequestHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent
import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.google.common.net.MediaType
import org.apache.http.entity.ContentType
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import kotlin.reflect.KClass
Expand Down Expand Up @@ -145,7 +145,7 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG

open fun <T> createResponse(input: APIGatewayProxyRequestEvent, response: ResponseEntity<T>): APIGatewayProxyResponseEvent {
// TODO add default accept type
val accept = MediaType.parse(input.acceptHeader())
val accept = ContentType.parse(input.acceptHeader())
return when {
response.body is Unit -> APIGatewayProxyResponseEvent()
.withStatusCode(204)
Expand Down
4 changes: 2 additions & 2 deletions router/src/main/kotlin/io/moia/router/RequestPredicate.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.moia.router

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
import com.google.common.net.MediaType
import org.apache.http.entity.ContentType

data class RequestPredicate(
val method: String,
Expand Down Expand Up @@ -34,7 +34,7 @@ data class RequestPredicate(
private fun contentTypeMatches(contentType: String?, accepted: Set<String>) =
if (accepted.isEmpty() && contentType == null) true
else if (contentType == null) false
else accepted.any { MediaType.parse(contentType).`is`(MediaType.parse(it)) }
else accepted.any { ContentType.parse(contentType).mimeType == ContentType.parse(it).mimeType }

companion object
}
Expand Down
18 changes: 9 additions & 9 deletions router/src/main/kotlin/io/moia/router/SerializationHandler.kt
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
package io.moia.router

import com.fasterxml.jackson.databind.ObjectMapper
import com.google.common.net.MediaType
import org.apache.http.entity.ContentType

interface SerializationHandler {

fun supports(acceptHeader: MediaType, response: ResponseEntity<*>): Boolean
fun supports(acceptHeader: ContentType, response: ResponseEntity<*>): Boolean

fun serialize(acceptHeader: MediaType, response: ResponseEntity<*>): String
fun serialize(acceptHeader: ContentType, response: ResponseEntity<*>): String
}

class SerializationHandlerChain(private val handlers: List<SerializationHandler>) :
SerializationHandler {

override fun supports(acceptHeader: MediaType, response: ResponseEntity<*>): Boolean =
override fun supports(acceptHeader: ContentType, response: ResponseEntity<*>): Boolean =
handlers.any { it.supports(acceptHeader, response) }

override fun serialize(acceptHeader: MediaType, response: ResponseEntity<*>): String =
override fun serialize(acceptHeader: ContentType, response: ResponseEntity<*>): String =
handlers.first { it.supports(acceptHeader, response) }.serialize(acceptHeader, response)
}

class JsonSerializationHandler(val objectMapper: ObjectMapper) : SerializationHandler {
class JsonSerializationHandler(private val objectMapper: ObjectMapper) : SerializationHandler {

private val json = MediaType.parse("application/json")
private val json = ContentType.parse("application/json")

override fun supports(acceptHeader: MediaType, response: ResponseEntity<*>): Boolean = acceptHeader.`is`(json)
override fun supports(acceptHeader: ContentType, response: ResponseEntity<*>): Boolean = acceptHeader.mimeType == json.mimeType

override fun serialize(acceptHeader: MediaType, response: ResponseEntity<*>): String =
override fun serialize(acceptHeader: ContentType, response: ResponseEntity<*>): String =
objectMapper.writeValueAsString(response.body)
}
18 changes: 17 additions & 1 deletion router/src/test/kotlin/io/moia/router/RequestHandlerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test

class RequestHandlerTest {

val testRequestHandler = TestRequestHandler()
private val testRequestHandler = TestRequestHandler()

@Test
fun `should match request`() {
Expand Down Expand Up @@ -186,6 +186,22 @@ class RequestHandlerTest {
assert(response.statusCode).isEqualTo(500)
}

@Test
fun `should handle request with a long accept header`() {

val response = testRequestHandler.handleRequest(
POST("/some")
.withHeaders(mapOf(
"Accept" to "application/json, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8",
"Content-Type" to "application/json"
))
.withBody("""{ "greeting": "some" }"""), mockk()
)

assert(response.statusCode).isEqualTo(200)
assert(response.body).isEqualTo("""{"greeting":"some"}""")
}

class TestRequestHandlerWithFilter : RequestHandler() {

var filterInvocations = 0
Expand Down