added explicit path calculator interface (#31)

This commit is contained in:
Ryan Brink
2021-04-20 10:17:05 -04:00
committed by GitHub
parent 40e8ec22ae
commit a0ab043e5a
6 changed files with 78 additions and 47 deletions

View File

@ -31,7 +31,8 @@ import org.leafygreens.kompendium.models.oas.OpenApiSpecReferenceObject
import org.leafygreens.kompendium.models.oas.OpenApiSpecRequest
import org.leafygreens.kompendium.models.oas.OpenApiSpecResponse
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaRef
import org.leafygreens.kompendium.util.Helpers.calculatePath
import org.leafygreens.kompendium.path.CorePathCalculator
import org.leafygreens.kompendium.path.PathCalculator
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
object Kompendium {
@ -44,12 +45,14 @@ object Kompendium {
paths = mutableMapOf()
)
var pathCalculator: PathCalculator = CorePathCalculator()
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified TParam : Any, reified TResp : Any> Route.notarizedGet(
info: MethodInfo,
noinline body: PipelineInterceptor<Unit, ApplicationCall>
): Route = notarizationPreFlight<TParam, Unit, TResp>() { paramType, requestType, responseType ->
val path = calculatePath()
val path = pathCalculator.calculate(this)
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
openApiSpec.paths[path]?.get = info.parseMethodInfo(HttpMethod.Get, paramType, requestType, responseType)
return method(HttpMethod.Get) { handle(body) }
@ -59,7 +62,7 @@ object Kompendium {
info: MethodInfo,
noinline body: PipelineInterceptor<Unit, ApplicationCall>
): Route = notarizationPreFlight<TParam, TReq, TResp>() { paramType, requestType, responseType ->
val path = calculatePath()
val path = pathCalculator.calculate(this)
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
openApiSpec.paths[path]?.post = info.parseMethodInfo(HttpMethod.Post, paramType, requestType, responseType)
return method(HttpMethod.Post) { handle(body) }
@ -69,7 +72,7 @@ object Kompendium {
info: MethodInfo,
noinline body: PipelineInterceptor<Unit, ApplicationCall>,
): Route = notarizationPreFlight<TParam, TReq, TResp>() { paramType, requestType, responseType ->
val path = calculatePath()
val path = pathCalculator.calculate(this)
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
openApiSpec.paths[path]?.put = info.parseMethodInfo(HttpMethod.Put, paramType, requestType, responseType)
return method(HttpMethod.Put) { handle(body) }
@ -79,7 +82,7 @@ object Kompendium {
info: MethodInfo,
noinline body: PipelineInterceptor<Unit, ApplicationCall>
): Route = notarizationPreFlight<TParam, Unit, TResp> { paramType, requestType, responseType ->
val path = calculatePath()
val path = pathCalculator.calculate(this)
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
openApiSpec.paths[path]?.delete = info.parseMethodInfo(HttpMethod.Delete, paramType, requestType, responseType)
return method(HttpMethod.Delete) { handle(body) }

View File

@ -0,0 +1,48 @@
package org.leafygreens.kompendium.path
import io.ktor.routing.PathSegmentConstantRouteSelector
import io.ktor.routing.PathSegmentParameterRouteSelector
import io.ktor.routing.RootRouteSelector
import io.ktor.routing.Route
import io.ktor.util.InternalAPI
import org.slf4j.LoggerFactory
open class CorePathCalculator : PathCalculator {
private val logger = LoggerFactory.getLogger(javaClass)
@OptIn(InternalAPI::class)
override fun calculate(
route: Route?,
tail: String
): String = when (route) {
null -> tail
else -> when (route.selector) {
is RootRouteSelector -> {
logger.debug("Root route detected, returning path: $tail")
tail
}
is PathSegmentParameterRouteSelector -> {
logger.debug("Found segment parameter ${route.selector}, continuing to parent")
val newTail = "/${route.selector}$tail"
calculate(route.parent, newTail)
}
is PathSegmentConstantRouteSelector -> {
logger.debug("Found segment constant ${route.selector}, continuing to parent")
val newTail = "/${route.selector}$tail"
calculate(route.parent, newTail)
}
else -> when (route.selector.javaClass.simpleName) {
"TrailingSlashRouteSelector" -> {
logger.debug("Found trailing slash route selector")
val newTail = tail.ifBlank { "/" }
calculate(route.parent, newTail)
}
else -> handleCustomSelectors(route, tail)
}
}
}
override fun handleCustomSelectors(route: Route, tail: String): String = error("Unknown selector ${route.selector}")
}

View File

@ -0,0 +1,11 @@
package org.leafygreens.kompendium.path
import io.ktor.routing.Route
interface PathCalculator {
fun calculate(route: Route?, tail: String = ""): String
fun handleCustomSelectors(route: Route, tail: String): String
}

View File

@ -18,47 +18,6 @@ object Helpers {
const val COMPONENT_SLUG = "#/components/schemas"
/**
* TODO Explain this
*/
@OptIn(InternalAPI::class)
fun Route.calculatePath(tail: String = ""): String {
logger.info("Building path for ${selector::class}")
return when (selector) {
is RootRouteSelector -> {
logger.info("Root route detected, returning path: $tail")
tail
}
is PathSegmentParameterRouteSelector -> {
logger.info("Found segment parameter $selector, continuing to parent")
val newTail = "/$selector$tail"
parent?.calculatePath(newTail) ?: run {
logger.info("No parent found, returning current path")
newTail
}
}
is PathSegmentConstantRouteSelector -> {
logger.info("Found segment constant $selector, continuing to parent")
val newTail = "/$selector$tail"
parent?.calculatePath(newTail) ?: run {
logger.info("No parent found, returning current path")
newTail
}
}
else -> when (selector.javaClass.simpleName) {
// dumb ass workaround to this object being internal to ktor
"TrailingSlashRouteSelector" -> {
logger.info("Found trailing slash route selector")
val newTail = tail.ifBlank { "/" }
parent?.calculatePath(newTail) ?: run {
logger.info("No parent found, returning current path")
newTail
}
}
else -> error("Unhandled selector type ${selector::class}")
}
}
}
/**
* Simple extension function that will take a [Pair] and place it (if absent) into a [MutableMap].