Skip to content

Commit 174fa41

Browse files
committed
cleaned the whole parameter parsing system, removed redundancies
1 parent 328df27 commit 174fa41

23 files changed

+459
-489
lines changed

src/main/kotlin/com/papsign/ktor/openapigen/annotations/parameters/QueryParam.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import com.papsign.ktor.openapigen.parameters.QueryParamStyle
88
@APIParam(ParameterLocation.query)
99
annotation class QueryParam(
1010
val description: String,
11-
val style: QueryParamStyle = QueryParamStyle.form,
11+
val style: QueryParamStyle = QueryParamStyle.DEFAULT,
1212
val explode: Boolean = true,
1313
val allowEmptyValues: Boolean = false,
1414
val deprecated: Boolean = false

src/main/kotlin/com/papsign/ktor/openapigen/modules/handlers/RouteHandler.kt

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ import com.papsign.ktor.openapigen.modules.providers.MethodProvider
1010
import com.papsign.ktor.openapigen.modules.providers.PathProvider
1111
import com.papsign.ktor.openapigen.openapi.Operation
1212
import com.papsign.ktor.openapigen.openapi.PathItem
13-
import com.papsign.ktor.openapigen.parameters.parsers.NoTranslation
14-
import com.papsign.ktor.openapigen.parameters.parsers.OpenAPIPathSegmentTranslator
15-
import com.papsign.ktor.openapigen.parameters.parsers.ParameterHandler
1613
import org.slf4j.Logger
1714
import org.slf4j.LoggerFactory
1815

@@ -24,8 +21,7 @@ object RouteHandler: HandlerModule {
2421
val methods = provider.ofClass<MethodProvider>()
2522
if (methods.size > 1) error("API cannot have two methods simultaneously: ${methods.map { it.method.value }}")
2623
val paths = provider.ofClass<PathProvider>()
27-
val translator = getTranslator(provider)
28-
val path = "/${paths.flatMap { it.path.split('/').filter(String::isNotEmpty).map(translator::translateSegment) }.joinToString("/")}"
24+
val path = "/${paths.flatMap { it.path.split('/').filter(String::isNotEmpty) }.joinToString("/")}"
2925
val operationModules = provider.ofClass<OperationModule>()
3026
apiGen.api.paths.getOrPut(path) { PathItem() }.also {pathItem ->
3127
methods.forEach {
@@ -39,11 +35,4 @@ object RouteHandler: HandlerModule {
3935
}
4036
log.trace("Registered $path::${methods.map { it.method.value }} with OpenAPI description with ${provider.ofClass<SelectedModule>().map { it.module::class.simpleName }}")
4137
}
42-
43-
private fun getTranslator(provider: ModuleProvider<*>): OpenAPIPathSegmentTranslator {
44-
val translator = provider.ofClass<OpenAPIPathSegmentTranslator>()
45-
if (translator.size > 1) log.warn("Too many Path Segment Translators, choosing first: $translator")
46-
if (translator.isEmpty()) log.debug("No Path Segment Translator, choosing default")
47-
return translator.firstOrNull() ?: NoTranslation
48-
}
4938
}

src/main/kotlin/com/papsign/ktor/openapigen/modules/openapi/HandlerModule.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.papsign.ktor.openapigen.modules.openapi
33
import com.papsign.ktor.openapigen.OpenAPIGen
44
import com.papsign.ktor.openapigen.modules.ModuleProvider
55
import com.papsign.ktor.openapigen.modules.OpenAPIModule
6-
import com.papsign.ktor.openapigen.parameters.parsers.ParameterHandler
76

87
interface HandlerModule: OpenAPIModule {
98
fun configure(apiGen: OpenAPIGen, provider: ModuleProvider<*>)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.papsign.ktor.openapigen.parameters
22

3-
enum class PathParamStyle(val prefix: String): ParameterStyle {
4-
simple(""), label("."), matrix(";")
3+
enum class PathParamStyle: ParameterStyle {
4+
DEFAULT, simple, label, matrix
55
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.papsign.ktor.openapigen.parameters
22

33
enum class QueryParamStyle: ParameterStyle {
4-
form, spaceDelimited, pipeDelimited, deepObject
4+
DEFAULT, form, spaceDelimited, pipeDelimited, deepObject
55
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.papsign.ktor.openapigen.parameters.handlers
2+
3+
import com.papsign.ktor.openapigen.parameters.parsers.ParameterParser
4+
import io.ktor.http.Parameters
5+
import kotlin.reflect.KFunction
6+
import kotlin.reflect.KParameter
7+
8+
class ModularParameterHander<T>(val parsers: Map<KParameter, ParameterParser>, val constructor: KFunction<T>) :
9+
ParameterHandler<T> {
10+
11+
override fun parse(parameters: Parameters): T {
12+
return constructor.callBy(parsers.mapValues { it.value.parse(parameters) })
13+
}
14+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.papsign.ktor.openapigen.parameters.handlers
2+
3+
import io.ktor.http.Parameters
4+
5+
interface ParameterHandler<T> {
6+
fun parse(parameters: Parameters): T
7+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.papsign.ktor.openapigen.parameters.parsers
2+
3+
import com.papsign.ktor.openapigen.parameters.PathParamStyle
4+
import com.papsign.ktor.openapigen.parameters.QueryParamStyle
5+
import com.papsign.ktor.openapigen.parameters.util.ParameterInfo
6+
import com.papsign.ktor.openapigen.parameters.util.primitiveParsers
7+
import io.ktor.http.Parameters
8+
import kotlin.reflect.KType
9+
10+
class CollectionParameterParser<T, A>(info: ParameterInfo, type: KType, val cvt: (List<T>?) -> A) :
11+
InfoParameterParser(info, { style ->
12+
when (style) {
13+
QueryParamStyle.DEFAULT -> QueryParamStyle.form
14+
QueryParamStyle.deepObject -> error("Deep Objects are not supported for Arrays")
15+
else -> style
16+
}
17+
}) {
18+
19+
private val parseFunc: (Parameters) -> A
20+
21+
init {
22+
val typeParser = primitiveParsers[type] as ((String?) -> T)? ?: error("Non-primitive Arrays aren't yet supported")
23+
val explodedParse = ({ parameters: Parameters -> cvt(parameters.getAll(key)?.map(typeParser)) })
24+
parseFunc = when (queryStyle) {
25+
QueryParamStyle.form -> {
26+
if (explode) {
27+
explodedParse
28+
} else {
29+
({ parameters: Parameters -> cvt(parameters[key]?.split(',')?.map(typeParser)) })
30+
}
31+
}
32+
QueryParamStyle.pipeDelimited -> {
33+
if (explode) {
34+
explodedParse
35+
} else {
36+
({ parameters: Parameters -> cvt(parameters[key]?.split('|')?.map(typeParser)) })
37+
}
38+
}
39+
QueryParamStyle.spaceDelimited -> {
40+
if (explode) {
41+
explodedParse
42+
} else {
43+
({ parameters: Parameters -> cvt(parameters[key]?.split(' ')?.map(typeParser)) })
44+
}
45+
}
46+
null -> null
47+
else -> error("Query param style $queryStyle is not supported for collections")
48+
} ?: when (pathStyle) {
49+
PathParamStyle.simple -> ({ parameters: Parameters -> cvt(parameters[key]?.split(',')?.map(typeParser)) })
50+
PathParamStyle.label -> {
51+
if (explode) {
52+
({ parameters: Parameters -> cvt(parameters[key]?.split('.')?.drop(1)?.map(typeParser)) })
53+
} else {
54+
({ parameters: Parameters -> cvt(parameters[key]?.removePrefix(".")?.split(',')?.map(typeParser)) })
55+
}
56+
}
57+
PathParamStyle.matrix -> {
58+
if (explode) {
59+
({ parameters: Parameters -> cvt(parameters[key]?.split(";$key=")?.drop(1)?.map(typeParser)) })
60+
} else {
61+
({ parameters: Parameters -> cvt(parameters[key]?.removePrefix(";$key=")?.split(',')?.map(typeParser)) })
62+
}
63+
}
64+
else -> error("Path param style $pathStyle is not supported for collections")
65+
}
66+
}
67+
68+
override fun parse(parameters: Parameters): Any? {
69+
return parseFunc(parameters)
70+
}
71+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.papsign.ktor.openapigen.parameters.parsers
2+
3+
import com.papsign.ktor.openapigen.classLogger
4+
import com.papsign.ktor.openapigen.parameters.PathParamStyle
5+
import com.papsign.ktor.openapigen.parameters.QueryParamStyle
6+
import com.papsign.ktor.openapigen.parameters.util.genPathParseFunc
7+
import com.papsign.ktor.openapigen.parameters.util.ParameterInfo
8+
import io.ktor.http.Parameters
9+
10+
class EnumParameterParser(info: ParameterInfo, val enumMap: Map<String, *>, val nullable: Boolean) : InfoParameterParser(info, { style ->
11+
when (style) {
12+
QueryParamStyle.DEFAULT, QueryParamStyle.form-> QueryParamStyle.form
13+
else -> {
14+
log.warn("Using non-form style for enum type, it is undefined in the OpenAPI standard, reverting to form style")
15+
QueryParamStyle.form
16+
}
17+
}
18+
}) {
19+
20+
private fun parse(parameter: String?): Any? {
21+
return parameter?.let { enumMap[it] }
22+
}
23+
24+
private val parseFunc = pathStyle?.let { genPathParseFunc(key, it, ::parse) } ?: ::parse
25+
26+
override fun parse(parameters: Parameters): Any? {
27+
return parseFunc(parameters[key])
28+
}
29+
30+
companion object {
31+
val log = classLogger<EnumParameterParser>()
32+
}
33+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.papsign.ktor.openapigen.parameters.parsers
2+
3+
import com.papsign.ktor.openapigen.parameters.PathParamStyle
4+
import com.papsign.ktor.openapigen.parameters.QueryParamStyle
5+
import com.papsign.ktor.openapigen.parameters.util.ParameterInfo
6+
7+
abstract class InfoParameterParser(
8+
info: ParameterInfo,
9+
queryStyle: (QueryParamStyle) -> QueryParamStyle,
10+
pathStyle: (PathParamStyle) -> PathParamStyle
11+
) : ParameterParser {
12+
13+
constructor(info: ParameterInfo, queryStyle: QueryParamStyle = QueryParamStyle.form, pathStyle: PathParamStyle = PathParamStyle.simple) : this(
14+
info,
15+
genReplace(QueryParamStyle.DEFAULT, queryStyle),
16+
genReplace(PathParamStyle.DEFAULT, pathStyle)
17+
)
18+
19+
constructor(info: ParameterInfo, queryStyle: (QueryParamStyle) -> QueryParamStyle, pathStyle: PathParamStyle = PathParamStyle.simple) : this(
20+
info,
21+
queryStyle,
22+
genReplace(PathParamStyle.DEFAULT, pathStyle)
23+
)
24+
25+
constructor(info: ParameterInfo, queryStyle: QueryParamStyle = QueryParamStyle.form, pathStyle: (PathParamStyle) -> PathParamStyle) : this(
26+
info,
27+
genReplace(QueryParamStyle.DEFAULT, queryStyle),
28+
pathStyle
29+
)
30+
31+
override val key: String = info.key
32+
override val pathStyle: PathParamStyle? = info.pathAnnotation?.style?.let(pathStyle)
33+
override val queryStyle: QueryParamStyle? = info.queryAnnotation?.style?.let(queryStyle)
34+
override val explode: Boolean = info.pathAnnotation?.explode ?: info.queryAnnotation!!.explode
35+
36+
companion object {
37+
private fun <T> genReplace(default: T, replace: T): (T) -> T {
38+
return { value ->
39+
when (value) {
40+
default -> replace
41+
else -> value
42+
}
43+
}
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)