All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.http4k.contract.ContractRoute.kt Maven / Gradle / Ivy

There is a newer version: 5.31.0.0
Show newest version
package org.http4k.contract


import org.http4k.core.*
import org.http4k.core.ContentType.Companion.APPLICATION_JSON
import org.http4k.core.Method.OPTIONS
import org.http4k.core.Status.Companion.OK
import org.http4k.lens.Header.CONTENT_TYPE
import org.http4k.lens.LensFailure
import org.http4k.lens.PathLens
import org.http4k.routing.Router

class ContractRoute internal constructor(internal val method: Method,
                                         internal val spec: ContractRouteSpec,
                                         internal val meta: RouteMeta,
                                         internal val toHandler: (ExtractedParts) -> HttpHandler) {

    internal val nonBodyParams = meta.requestParams.plus(spec.pathLenses).flatMap { it }

    internal val jsonRequest: RequestMeta? = meta.request?.let { if (CONTENT_TYPE(it.message) == APPLICATION_JSON) it else null }

    internal val tags = meta.tags.toSet().sortedBy { it.name }

    fun newRequest(baseUri: Uri): Request = Request(method, "").uri(baseUri.path(spec.describe(Root)))

    internal fun toRouter(contractRoot: PathSegments): Router = object : Router {

        override fun toString(): String = "${method.name}: ${spec.describe(contractRoot)}"

        override fun match(request: Request): HttpHandler? =
            if ((request.method == OPTIONS || request.method == method) && request.pathSegments().startsWith(spec.pathFn(contractRoot))) {
                try {
                    request.without(spec.pathFn(contractRoot))
                        .extract(spec.pathLenses.toList())
                        ?.let {
                            if (request.method == OPTIONS) {
                                { Response(OK) }
                            } else spec.then(toHandler(it))
                        }
                } catch (e: LensFailure) {
                    null
                }
            } else null
    }

    internal fun describeFor(contractRoot: PathSegments): String = spec.describe(contractRoot)

    override fun toString(): String = "${method.name}: ${spec.describe(Root)}"
}

internal class ExtractedParts(private val mapping: Map, *>) {
    @Suppress("UNCHECKED_CAST")
    operator fun  get(lens: PathLens): T = mapping[lens] as T
}

private operator fun  PathSegments.invoke(index: Int, fn: (String) -> T): T? = toList().let { if (it.size > index) fn(it[index]) else null }

private fun PathSegments.extract(lenses: List>): ExtractedParts? =
    if (this.toList().size == lenses.size) ExtractedParts(lenses.mapIndexed { index, lens -> lens to this(index, lens::invoke) }.toMap()) else null





© 2015 - 2024 Weber Informatics LLC | Privacy Policy