
org.http4k.routing.spa.kt Maven / Gradle / Ivy
package org.http4k.routing
import org.http4k.core.ContentType
import org.http4k.core.Filter
import org.http4k.core.Method.GET
import org.http4k.core.Method.OPTIONS
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status.Companion.NOT_FOUND
import org.http4k.routing.RouterMatch.MatchingHandler
import org.http4k.routing.RouterMatch.MethodNotMatched
/**
* For SPAs we serve static content as usual, or fall back to the index page. The resource loader is configured to look at
* /public package (on the Classpath).
*/
fun singlePageApp(
resourceLoader: ResourceLoader = ResourceLoader.Classpath("/public"),
vararg extraFileExtensionToContentTypes: Pair
): RoutingHttpHandler =
SinglePageAppRoutingHandler(
"",
StaticRoutingHttpHandler("", resourceLoader, extraFileExtensionToContentTypes.asList().toMap())
)
internal data class SinglePageAppRoutingHandler(
private val pathSegments: String,
private val staticHandler: StaticRoutingHttpHandler
) : RoutingHttpHandler {
override fun invoke(request: Request): Response {
val matchOnStatic = when (val matchResult = staticHandler.match(request)) {
is MatchingHandler -> matchResult(request)
else -> null
}
val matchOnIndex = when (val matchResult = staticHandler.match(Request(GET, pathSegments))) {
is MatchingHandler -> matchResult
else -> null
}
val fallbackHandler = matchOnIndex ?: { Response(NOT_FOUND) }
return matchOnStatic ?: fallbackHandler(Request(GET, pathSegments))
}
override fun match(request: Request) = when (request.method) {
OPTIONS -> MethodNotMatched(RouterDescription("template == '$pathSegments'"))
else -> MatchingHandler(this, description)
}
override fun withFilter(new: Filter) =
copy(staticHandler = staticHandler.withFilter(new) as StaticRoutingHttpHandler)
override fun withBasePath(new: String) =
SinglePageAppRoutingHandler(new + pathSegments, staticHandler.withBasePath(new) as StaticRoutingHttpHandler)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy