Skip to content

Commit

Permalink
chore: implement add PredicateFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
mabels committed May 2, 2024
1 parent 0e8e22b commit d94ed84
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 22 deletions.
44 changes: 31 additions & 13 deletions router/src/main/kotlin/io/moia/router/RequestPredicate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,38 @@ import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
import com.google.common.net.MediaType
import isCompatibleWith

open class RequestPredicate(
val method: String,
val pathPattern: String,
var produces: Set<String>,
var consumes: Set<String>,
var requiredPermissions: Set<String> = emptySet()
) {
interface RequestPredicate {
fun consuming(vararg mediaTypes: String): RequestPredicate
fun producing(vararg mediaTypes: String): RequestPredicate

fun requiringPermissions(vararg permissions: String): RequestPredicate

fun match(request: APIGatewayProxyRequestEvent): RequestMatchResult
fun matchedAcceptType(acceptedMediaTypes: List<MediaType>): MediaType?

val pathPattern: String

val method: String
var consumes: Set<String>
var produces: Set<String>

var requiredPermissions: Set<String>
}

open class RequestPredicateImpl(
override val method: String,
override val pathPattern: String,
override var produces: Set<String>,
override var consumes: Set<String>,
): RequestPredicate {

fun consuming(vararg mediaTypes: String): RequestPredicate {
override var requiredPermissions: Set<String> = emptySet()
override fun consuming(vararg mediaTypes: String): RequestPredicate {
consumes = mediaTypes.toSet()
return this
}

fun producing(vararg mediaTypes: String): RequestPredicate {
override fun producing(vararg mediaTypes: String): RequestPredicate {
produces = mediaTypes.toSet()
return this
}
Expand All @@ -42,12 +60,12 @@ open class RequestPredicate(
* Register required permissions for this route.
* The RequestHandler checks if any of the given permissions are found on a request.
*/
fun requiringPermissions(vararg permissions: String): RequestPredicate {
override fun requiringPermissions(vararg permissions: String): RequestPredicate {
requiredPermissions = permissions.toSet()
return this
}

internal fun match(request: APIGatewayProxyRequestEvent) =
override fun match(request: APIGatewayProxyRequestEvent) =
RequestMatchResult(
matchPath = pathMatches(request),
matchMethod = methodMatches(request),
Expand All @@ -63,7 +81,7 @@ open class RequestPredicate(
* Find the media type that is compatible with the one the client requested out of the ones that the the handler can produce
* Talking into account that an accept header can contain multiple media types (e.g. application/xhtml+xml, application/json)
*/
fun matchedAcceptType(acceptedMediaTypes: List<MediaType>) =
override fun matchedAcceptType(acceptedMediaTypes: List<MediaType>) =
produces
.map { MediaType.parse(it) }
.firstOrNull { acceptedMediaTypes.any { acceptedType -> it.isCompatibleWith(acceptedType) } }
Expand All @@ -79,7 +97,7 @@ open class RequestPredicate(
}
}

internal data class RequestMatchResult(
data class RequestMatchResult(
val matchPath: Boolean = false,
val matchMethod: Boolean = false,
val matchAcceptType: Boolean = false,
Expand Down
24 changes: 15 additions & 9 deletions router/src/main/kotlin/io/moia/router/Router.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent.ProxyRequestContext
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent

class Router {
typealias PredicateFactory = (String, String, Set<String>, Set<String>) -> RequestPredicate

class Router(private val predicateFactory: PredicateFactory) {

val routes = mutableListOf<RouterFunction<*, *>>()

Expand Down Expand Up @@ -51,16 +53,20 @@ class Router {
method: String,
handlerFunction: HandlerFunction<I, T>,
consuming: Set<String> = defaultConsuming
) =
RequestPredicate(
method = method,
pathPattern = pattern,
consumes = consuming,
produces = defaultProducing
).also { routes += RouterFunction(it, handlerFunction) }
) = predicateFactory(method, pattern, consuming, defaultProducing)
.also { routes += RouterFunction(it, handlerFunction) }

companion object {
fun router(routes: Router.() -> Unit) = Router().apply(routes)

fun defaultPredicateFactory(method: String, pattern: String, consuming: Set<String>, producing: Set<String>): RequestPredicate =
RequestPredicateImpl(
method = method,
pathPattern = pattern,
consumes = consuming,
produces = producing
)
fun router(routes: Router.() -> Unit) = Router(Router::defaultPredicateFactory).apply(routes)
fun router(factory: PredicateFactory, routes: Router.() -> Unit) = Router(factory).apply(routes)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ class RequestHandlerTest {
fun `should fail for function references when using Kotlin 1_6_10`() {
class DummyHandler : RequestHandler() {
val dummy = object {
@Suppress("UNUSED_PARAMETER")
fun handler(r: Request<Unit>) = ResponseEntity.ok(Unit)
}
override fun exceptionToResponseEntity(ex: Exception) = throw ex
Expand Down

0 comments on commit d94ed84

Please sign in to comment.