Skip to content

Commit

Permalink
support ktor 3
Browse files Browse the repository at this point in the history
ktor 3.0.1
kotlin 2.0.21
  • Loading branch information
darkxanter committed Oct 30, 2024
1 parent 94d3228 commit 9879ff4
Show file tree
Hide file tree
Showing 31 changed files with 686 additions and 540 deletions.
6 changes: 6 additions & 0 deletions detekt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
style:
MaxLineLength:
active: false
naming:
MemberNameEqualsClassName:
active: false
12 changes: 6 additions & 6 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[versions]
slf4j = "2.0.12"
logback = "1.4.12"
ktor = "2.3.11"
junit = "5.10.2"
kotlin = "1.8.22"
dokka = "1.8.20"
logback = "1.5.10"
ktor = "3.0.1"
junit = "5.11.3"
kotlin = "2.0.21"
dokka = "1.9.20"
# we can not switch to 3.x.x because we want to keep it compatible with JVM 8
nemerosaVersioning = "2.15.1"
nexusPublish = "1.1.0"
# when updating version here, don't forge to update version in OpenAPIGen.kt line 68
swaggerUi = "5.17.2"
reflections = "0.10.2"
jackson = "2.17.1"
jackson = "2.18.1"
axion = "1.15.1"

[libraries]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.papsign.ktor.openapigen.content.type

import io.ktor.http.ContentType
import io.ktor.server.application.ApplicationCall
import io.ktor.util.pipeline.PipelineContext
import io.ktor.server.routing.RoutingContext
import kotlin.reflect.KType

interface BodyParser: ContentTypeProvider {
fun <T: Any> getParseableContentTypes(type: KType): List<ContentType>
suspend fun <T: Any> parseBody(clazz: KType, request: PipelineContext<Unit, ApplicationCall>): T
suspend fun <T: Any> parseBody(clazz: KType, request: RoutingContext): T
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ package com.papsign.ktor.openapigen.content.type
import com.papsign.ktor.openapigen.route.response.Responder
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.ApplicationCall
import io.ktor.util.pipeline.PipelineContext
import io.ktor.server.routing.RoutingContext

data class ContentTypeResponder(val responseSerializer: ResponseSerializer, val contentType: ContentType): Responder {
override suspend fun <T : Any> respond(response: T, request: PipelineContext<Unit, ApplicationCall>) {
override suspend fun <T : Any> respond(response: T, request: RoutingContext) {
responseSerializer.respond(response, request, contentType)
}

override suspend fun <T : Any> respond(statusCode: HttpStatusCode, response: T, request: PipelineContext<Unit, ApplicationCall>) {
override suspend fun <T : Any> respond(statusCode: HttpStatusCode, response: T, request: RoutingContext) {
responseSerializer.respond(statusCode, response, request, contentType)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ package com.papsign.ktor.openapigen.content.type

import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.ApplicationCall
import io.ktor.util.pipeline.PipelineContext
import io.ktor.server.routing.RoutingContext
import kotlin.reflect.KType

interface ResponseSerializer: ContentTypeProvider {
/**
* used to determine which registered response serializer is used, based on the accept header
*/
fun <T: Any> getSerializableContentTypes(type: KType): List<ContentType>
suspend fun <T: Any> respond(response: T, request: PipelineContext<Unit, ApplicationCall>, contentType: ContentType)
suspend fun <T: Any> respond(statusCode: HttpStatusCode, response: T, request: PipelineContext<Unit, ApplicationCall>, contentType: ContentType)
suspend fun <T: Any> respond(response: T, request: RoutingContext, contentType: ContentType)
suspend fun <T: Any> respond(statusCode: HttpStatusCode, response: T, request: RoutingContext, contentType: ContentType)
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
package com.papsign.ktor.openapigen.content.type.binary

import com.papsign.ktor.openapigen.*
import com.papsign.ktor.openapigen.OpenAPIGen
import com.papsign.ktor.openapigen.OpenAPIGenModuleExtension
import com.papsign.ktor.openapigen.annotations.Response
import com.papsign.ktor.openapigen.content.type.BodyParser
import com.papsign.ktor.openapigen.content.type.ContentTypeProvider
import com.papsign.ktor.openapigen.content.type.ResponseSerializer
import com.papsign.ktor.openapigen.exceptions.assertContent
import com.papsign.ktor.openapigen.getKType
import com.papsign.ktor.openapigen.model.operation.MediaTypeModel
import com.papsign.ktor.openapigen.model.schema.DataFormat
import com.papsign.ktor.openapigen.model.schema.DataType
import com.papsign.ktor.openapigen.model.schema.SchemaModel
import com.papsign.ktor.openapigen.modules.ModuleProvider
import com.papsign.ktor.openapigen.unitKType
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.ApplicationCall
import io.ktor.server.request.receiveStream
import io.ktor.server.response.respondBytes
import io.ktor.util.pipeline.PipelineContext
import io.ktor.server.routing.RoutingContext
import java.io.InputStream
import kotlin.reflect.*
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.KProperty1
import kotlin.reflect.KType
import kotlin.reflect.KVisibility
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.jvm.jvmErasure
Expand All @@ -37,21 +43,21 @@ object BinaryContentTypeParser: BodyParser, ResponseSerializer, OpenAPIGenModule
return type.jvmErasure.findAnnotation<BinaryResponse>()?.contentTypes?.map(ContentType.Companion::parse) ?: listOf()
}

override suspend fun <T : Any> respond(response: T, request: PipelineContext<Unit, ApplicationCall>, contentType: ContentType) {
override suspend fun <T : Any> respond(response: T, request: RoutingContext, contentType: ContentType) {
val code = response::class.findAnnotation<Response>()?.statusCode?.let { HttpStatusCode.fromValue(it) } ?: HttpStatusCode.OK
respond(code, response, request, contentType)
}

override suspend fun <T : Any> respond(statusCode: HttpStatusCode, response: T, request: PipelineContext<Unit, ApplicationCall>, contentType: ContentType) {
override suspend fun <T : Any> respond(statusCode: HttpStatusCode, response: T, request: RoutingContext, contentType: ContentType) {
@Suppress("UNCHECKED_CAST")
val prop = response::class.declaredMemberProperties.first { it.visibility == KVisibility.PUBLIC } as KProperty1<T, *>
val data = prop.get(response) as InputStream
request.context.respondBytes(data.readBytes(), contentType, statusCode)
request.call.respondBytes(data.readBytes(), contentType, statusCode)
}

@Suppress("UNCHECKED_CAST")
override suspend fun <T : Any> parseBody(clazz: KType, request: PipelineContext<Unit, ApplicationCall>): T {
return (clazz.classifier as KClass<T>).getAcceptableConstructor().call( request.context.receiveStream())
override suspend fun <T : Any> parseBody(clazz: KType, request: RoutingContext): T {
return (clazz.classifier as KClass<T>).getAcceptableConstructor().call( request.call.receiveStream())
}

override fun <T> getMediaType(type: KType, apiGen: OpenAPIGen, provider: ModuleProvider<*>, example: T?, usage: ContentTypeProvider.Usage): Map<ContentType, MediaTypeModel<T>>? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,15 @@ import com.papsign.ktor.openapigen.schema.builder.provider.FinalSchemaBuilderPro
import com.papsign.ktor.openapigen.unitKType
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.ApplicationCall
import io.ktor.server.application.PluginBuilder
import io.ktor.server.application.PluginInstance
import io.ktor.server.application.call
import io.ktor.server.application.pluginOrNull
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.plugins.contentnegotiation.ContentNegotiationConfig
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.util.pipeline.PipelineContext
import io.ktor.server.routing.RoutingContext
import io.ktor.util.reflect.TypeInfo
import io.ktor.util.reflect.platformType
import kotlin.reflect.KProperty1
import kotlin.reflect.KType
import kotlin.reflect.full.findAnnotation
Expand Down Expand Up @@ -111,10 +108,10 @@ object KtorContentProvider : ContentTypeProvider, BodyParser, ResponseSerializer
return contentTypes!!.toList()
}

override suspend fun <T : Any> parseBody(clazz: KType, request: PipelineContext<Unit, ApplicationCall>): T {
override suspend fun <T : Any> parseBody(clazz: KType, request: RoutingContext): T {
val info = TypeInfo(
type = clazz.jvmErasure,
reifiedType = clazz.platformType,
// reifiedType = clazz.platformType,
kotlinType = clazz
)
return request.call.receive(info)
Expand All @@ -126,7 +123,7 @@ object KtorContentProvider : ContentTypeProvider, BodyParser, ResponseSerializer

override suspend fun <T : Any> respond(
response: T,
request: PipelineContext<Unit, ApplicationCall>,
request: RoutingContext,
contentType: ContentType
) {
request.call.respond(response as Any)
Expand All @@ -135,7 +132,7 @@ object KtorContentProvider : ContentTypeProvider, BodyParser, ResponseSerializer
override suspend fun <T : Any> respond(
statusCode: HttpStatusCode,
response: T,
request: PipelineContext<Unit, ApplicationCall>,
request: RoutingContext,
contentType: ContentType
) {
request.call.respond(statusCode, response as Any)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.papsign.ktor.openapigen.content.type.multipart

import com.papsign.ktor.openapigen.*
import com.papsign.ktor.openapigen.OpenAPIGen
import com.papsign.ktor.openapigen.OpenAPIGenModuleExtension
import com.papsign.ktor.openapigen.annotations.mapping.openAPIName
import com.papsign.ktor.openapigen.content.type.BodyParser
import com.papsign.ktor.openapigen.content.type.ContentTypeProvider
import com.papsign.ktor.openapigen.exceptions.OpenAPIParseException
import com.papsign.ktor.openapigen.exceptions.assertContent
import com.papsign.ktor.openapigen.getKType
import com.papsign.ktor.openapigen.isValue
import com.papsign.ktor.openapigen.model.operation.MediaTypeEncodingModel
import com.papsign.ktor.openapigen.model.operation.MediaTypeModel
import com.papsign.ktor.openapigen.model.schema.SchemaModel
Expand All @@ -15,14 +18,23 @@ import com.papsign.ktor.openapigen.parameters.util.localDateTimeFormatter
import com.papsign.ktor.openapigen.parameters.util.offsetDateTimeFormatter
import com.papsign.ktor.openapigen.parameters.util.zonedDateTimeFormatter
import com.papsign.ktor.openapigen.schema.builder.provider.FinalSchemaBuilderProviderModule
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.util.*
import io.ktor.util.pipeline.*
import com.papsign.ktor.openapigen.unitKType
import com.papsign.ktor.openapigen.unwrappedType
import io.ktor.http.ContentType
import io.ktor.http.content.PartData
import io.ktor.http.content.forEachPart
import io.ktor.http.content.streamProvider
import io.ktor.server.request.receiveMultipart
import io.ktor.server.routing.RoutingContext
import io.ktor.util.asStream
import java.io.InputStream
import java.time.*
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.OffsetTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.util.*
import kotlin.collections.set
Expand Down Expand Up @@ -105,9 +117,9 @@ object MultipartFormDataContentProvider : BodyParser, OpenAPIGenModuleExtension

private val typeContentTypes = HashMap<KType, Map<String, MediaTypeEncodingModel>>()

override suspend fun <T : Any> parseBody(clazz: KType, request: PipelineContext<Unit, ApplicationCall>): T {
override suspend fun <T : Any> parseBody(clazz: KType, request: RoutingContext): T {
val objectMap = HashMap<String, Any>()
request.context.receiveMultipart().forEachPart {
request.call.receiveMultipart().forEachPart {
val name = it.name
if (name != null) {
when (it) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import com.papsign.ktor.openapigen.modules.OpenAPIModule
import com.papsign.ktor.openapigen.modules.handlers.AuthHandler
import com.papsign.ktor.openapigen.route.path.auth.OpenAPIAuthenticatedRoute
import com.papsign.ktor.openapigen.route.path.normal.NormalOpenAPIRoute
import io.ktor.server.application.ApplicationCall
import io.ktor.util.pipeline.PipelineContext
import io.ktor.server.routing.RoutingContext
import kotlin.reflect.KType

interface AuthProvider<TAuth>: OpenAPIModule, DependentModule {
suspend fun getAuth(pipeline: PipelineContext<Unit, ApplicationCall>): TAuth
suspend fun getAuth(pipeline: RoutingContext): TAuth
fun apply(route: NormalOpenAPIRoute): OpenAPIAuthenticatedRoute<TAuth>
val security: Iterable<Iterable<Security<*>>>
override val handlers: Collection<Pair<KType, OpenAPIModule>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.papsign.ktor.openapigen.route
import com.papsign.ktor.openapigen.APITag
import com.papsign.ktor.openapigen.annotations.Path
import com.papsign.ktor.openapigen.content.type.ContentTypeProvider
import com.papsign.ktor.openapigen.getKType
import com.papsign.ktor.openapigen.modules.handlers.RequestHandlerModule
import com.papsign.ktor.openapigen.modules.handlers.ResponseHandlerModule
import com.papsign.ktor.openapigen.modules.registerModule
Expand All @@ -12,13 +11,12 @@ import com.papsign.ktor.openapigen.route.modules.PathProviderModule
import io.ktor.http.HttpMethod
import io.ktor.server.routing.HttpMethodRouteSelector
import io.ktor.server.routing.createRouteFromPath
import io.ktor.util.KtorDsl
import io.ktor.utils.io.KtorDsl
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection
import kotlin.reflect.KVariance
import kotlin.reflect.full.createType
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.starProjectedType
import kotlin.reflect.jvm.jvmErasure
import kotlin.reflect.typeOf

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.papsign.ktor.openapigen.route

import com.papsign.ktor.openapigen.classLogger
import com.papsign.ktor.openapigen.content.type.*
import com.papsign.ktor.openapigen.content.type.BodyParser
import com.papsign.ktor.openapigen.content.type.ContentTypeResponder
import com.papsign.ktor.openapigen.content.type.ResponseSerializer
import com.papsign.ktor.openapigen.content.type.SelectedParser
import com.papsign.ktor.openapigen.content.type.SelectedSerializer
import com.papsign.ktor.openapigen.content.type.ktor.KtorContentProvider
import com.papsign.ktor.openapigen.exceptions.OpenAPINoParserException
import com.papsign.ktor.openapigen.exceptions.OpenAPINoSerializerException
Expand All @@ -15,15 +19,12 @@ import com.papsign.ktor.openapigen.parameters.util.buildParameterHandler
import com.papsign.ktor.openapigen.route.response.Responder
import com.papsign.ktor.openapigen.validation.ValidationHandler
import io.ktor.http.ContentType
import io.ktor.server.application.ApplicationCall
import io.ktor.server.application.call
import io.ktor.server.request.contentType
import io.ktor.server.routing.Route
import io.ktor.server.routing.RoutingContext
import io.ktor.server.routing.accept
import io.ktor.server.routing.application
import io.ktor.server.routing.contentType
import io.ktor.util.pipeline.PipelineContext
import io.ktor.util.reflect.TypeInfo
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection
import kotlin.reflect.KVariance
Expand All @@ -38,7 +39,7 @@ abstract class OpenAPIRoute<T : OpenAPIRoute<T>>(val ktorRoute: Route, val provi
paramsType: KType,
responseType: KType,
bodyType: KType,
pass: suspend OpenAPIRoute<*>.(pipeline: PipelineContext<Unit, ApplicationCall>, responder: Responder, P, B) -> Unit
pass: suspend OpenAPIRoute<*>.(pipeline: RoutingContext, responder: Responder, P, B) -> Unit
) {
val parameterHandler = buildParameterHandler<P>(paramsType)
provider.registerModule(parameterHandler, ParameterHandler::class.createType(listOf(KTypeProjection(KVariance.INVARIANT, paramsType))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import com.papsign.ktor.openapigen.route.path.normal.NormalOpenAPIRoute
import io.ktor.server.application.Application
import io.ktor.server.application.plugin
import io.ktor.server.routing.Routing
import io.ktor.server.routing.application
import io.ktor.server.routing.routing
import io.ktor.util.KtorDsl
import io.ktor.utils.io.KtorDsl

/**
* Wrapper for [io.ktor.routing.routing] to create the endpoints while configuring OpenAPI
Expand Down
5 changes: 3 additions & 2 deletions src/main/kotlin/com/papsign/ktor/openapigen/route/Throws.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import com.papsign.ktor.openapigen.modules.providers.ThrowInfoProvider
import com.papsign.ktor.openapigen.modules.registerModule
import com.papsign.ktor.openapigen.route.util.createConstantChild
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.ApplicationCall
import io.ktor.server.application.ApplicationCallPipeline
import io.ktor.server.application.PipelineCall
import io.ktor.server.application.call
import io.ktor.server.response.respond
import io.ktor.server.routing.intercept
import io.ktor.util.pipeline.PipelineContext
import kotlinx.coroutines.coroutineScope
import kotlin.reflect.KClass
Expand Down Expand Up @@ -60,7 +61,7 @@ inline fun <T: OpenAPIRoute<T>> T.throws(vararg responses: APIException<*, *>, c
}
}

fun makeExceptionHandler(info: Array<out APIException<*, *>>): suspend PipelineContext<*, ApplicationCall>.(t: Throwable) -> Unit {
fun makeExceptionHandler(info: Array<out APIException<*, *>>): suspend PipelineContext<*, PipelineCall>.(t: Throwable) -> Unit {
val classes = info.associateBy { it.exceptionClass }
fun findHandlerByType(clazz: KClass<*>): APIException<*, *>? {
classes[clazz]?.let { return it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.papsign.ktor.openapigen.route.method
import com.papsign.ktor.openapigen.route.preHandle
import com.papsign.ktor.openapigen.route.response.OpenAPIPipelineAuthContext
import io.ktor.http.HttpMethod
import io.ktor.util.KtorDsl
import io.ktor.utils.io.KtorDsl
import kotlin.reflect.full.starProjectedType
import kotlin.reflect.typeOf

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.papsign.ktor.openapigen.route.method
import com.papsign.ktor.openapigen.route.preHandle
import com.papsign.ktor.openapigen.route.response.OpenAPIPipelineResponseContext
import io.ktor.http.HttpMethod
import io.ktor.util.KtorDsl
import io.ktor.utils.io.KtorDsl
import kotlin.reflect.full.starProjectedType
import kotlin.reflect.typeOf

Expand Down
Loading

0 comments on commit 9879ff4

Please sign in to comment.