Skip to content

Commit

Permalink
further changes to module routing
Browse files Browse the repository at this point in the history
  • Loading branch information
daviddenton committed May 30, 2017
1 parent d62d624 commit fff5143
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 9 deletions.
4 changes: 4 additions & 0 deletions http4k-core/src/main/kotlin/org/http4k/core/Http4k.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.http4k.core

import org.http4k.routing.RoutingHttpHandler

typealias HttpHandler = (Request) -> Response

interface Filter : (HttpHandler) -> HttpHandler {
Expand All @@ -10,6 +12,8 @@ interface Filter : (HttpHandler) -> HttpHandler {
}
}

fun Filter.then(router: RoutingHttpHandler): RoutingHttpHandler = router.copy(filter = this)

fun Filter.then(next: Filter): Filter = Filter { this(next(it)) }

fun Filter.then(next: HttpHandler): HttpHandler = { this(next)(it) }
Expand Down
14 changes: 9 additions & 5 deletions http4k-core/src/main/kotlin/org/http4k/routing/Routing.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.http4k.routing

import org.http4k.core.Filter
import org.http4k.core.HttpHandler
import org.http4k.core.Method
import org.http4k.core.Request
Expand All @@ -8,26 +9,29 @@ import org.http4k.core.Status.Companion.NOT_FOUND
import org.http4k.core.UriTemplate
import org.http4k.core.UriTemplate.Companion.from
import org.http4k.core.findSingle
import org.http4k.core.then

data class Route(val method: Method, val template: UriTemplate, val handler: HttpHandler)

fun routes(vararg routes: Route): RoutesRouter = RoutesRouter(routes.asList())
fun routes(vararg routes: Route): RoutingHttpHandler = RoutingHttpHandler(routes.asList())

fun routes(module: Module, vararg then: Module): HttpHandler = then.fold(module) { memo, next -> memo.then(next) }.toHttpHandler()

fun Request.path(name: String): String? = uriTemplate().extract(uri.toString())[name]

infix fun Pair<Method, String>.by(action: HttpHandler): Route = Route(first, from(second), action)

infix fun String.by(router: RoutesRouter): Module = object : Module {
override fun toRouter(): Router = RoutesRouter(router.routes.map { it.copy(template = it.template.prefixedWith(this@by)) })
infix fun String.by(router: RoutingHttpHandler): Module = object : Module {
override fun toRouter(): Router = RoutingHttpHandler(router.routes.map { it.copy(template = it.template.prefixedWith(this@by)) })
}

data class RoutesRouter(internal val routes: List<Route>) : Router, HttpHandler {
data class RoutingHttpHandler(internal val routes: List<Route>, internal val filter: Filter? = null) : Router, HttpHandler {
private val routers = routes.map(Route::asRouter)
private val noMatch: HttpHandler? = null

override fun invoke(request: Request): Response = match(request)?.invoke(request) ?: Response(NOT_FOUND.description("Route not found"))
override fun invoke(request: Request) = match(request)
?.let { handler -> (filter?.then(handler) ?: handler).invoke(request) }
?: Response(NOT_FOUND.description("Route not found"))

override fun match(request: Request): HttpHandler? = routers.fold(noMatch, { memo, router -> memo ?: router.match(request) })
}
Expand Down
12 changes: 12 additions & 0 deletions http4k-core/src/test/kotlin/org/http4k/routing/RoutingTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package org.http4k.routing

import com.natpryce.hamkrest.assertion.assertThat
import com.natpryce.hamkrest.equalTo
import org.http4k.core.Filter
import org.http4k.core.Method.GET
import org.http4k.core.Method.POST
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status.Companion.METHOD_NOT_ALLOWED
import org.http4k.core.Status.Companion.NOT_FOUND
import org.http4k.core.Status.Companion.OK
import org.http4k.core.then
import org.junit.Assert.fail
import org.junit.Ignore
import org.junit.Test
Expand Down Expand Up @@ -135,4 +137,14 @@ class RoutingTest {
assertThat(app(Request(GET, "/asd/a/something")).status, equalTo(NOT_FOUND))
}

@Test
fun `can apply a filter to a Router`() {
val routes = Filter { next -> { next(it.header("name", "value")) } }
.then(routes(
GET to "/a/thing" by { Response(OK).body(it.header("name")!!) }
))

assertThat(routes(Request(GET, "/a/thing")).bodyString(), equalTo("value"))
}

}
13 changes: 9 additions & 4 deletions src/test/kotlin/cookbook/module_routing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@ import org.http4k.core.Method.POST
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status.Companion.OK
import org.http4k.core.then
import org.http4k.filter.DebuggingFilters.PrintRequestAndResponse
import org.http4k.routing.by
import org.http4k.routing.path
import org.http4k.routing.routes

fun main(args: Array<String>) {

val routes = routes(
GET to "/get/{name}" by { req: Request -> Response(OK).body(req.path("name")!!) },
POST to "/post/{name}" by { _: Request -> Response(OK) }
)
val routes =
PrintRequestAndResponse().then(
routes(
GET to "/get/{name}" by { req: Request -> Response(OK).body(req.path("name")!!) },
POST to "/post/{name}" by { _: Request -> Response(OK) }
)
)
println(routes(Request(GET, "/get/value")))

val app = routes(
Expand Down

0 comments on commit fff5143

Please sign in to comment.