Skip to content

Commit c2b7932

Browse files
committed
Removed oauth2 interop because it's not a resource server, needs rework
added sealed class support, subclasses will be interpreted as 'OneOf'
1 parent b5269bd commit c2b7932

File tree

6 files changed

+58
-189
lines changed

6 files changed

+58
-189
lines changed

src/main/kotlin/com/papsign/ktor/openapigen/content/type/ktor/KtorContentProvider.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.papsign.ktor.openapigen.content.type.ktor
22

3+
import com.fasterxml.jackson.databind.JsonMappingException
4+
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException
5+
import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
36
import com.papsign.kotlin.reflection.allTypes
47
import com.papsign.kotlin.reflection.getKType
58
import com.papsign.kotlin.reflection.unitKType
@@ -25,6 +28,7 @@ import io.ktor.features.ContentNegotiation
2528
import io.ktor.http.ContentType
2629
import io.ktor.http.HttpStatusCode
2730
import io.ktor.request.receive
31+
import io.ktor.request.receiveOrNull
2832
import io.ktor.response.respond
2933
import io.ktor.util.pipeline.PipelineContext
3034
import kotlin.reflect.KClass

src/main/kotlin/com/papsign/ktor/openapigen/interop/OAuth2Provider.kt

Lines changed: 0 additions & 101 deletions
This file was deleted.

src/main/kotlin/com/papsign/ktor/openapigen/modules/schema/SimpleSchemaRegistrar.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import kotlin.reflect.KType
88
import kotlin.reflect.KVisibility
99
import kotlin.reflect.full.declaredMemberProperties
1010
import kotlin.reflect.full.isSubclassOf
11+
import kotlin.reflect.full.starProjectedType
1112
import kotlin.reflect.jvm.jvmErasure
1213

1314
open class SimpleSchemaRegistrar(val namer: SchemaNamer) : SchemaRegistrar {
@@ -50,8 +51,11 @@ open class SimpleSchemaRegistrar(val namer: SchemaNamer) : SchemaRegistrar {
5051
}
5152

5253
private fun SchemaRegistrar.makeObjectSchema(type: KType): Schema<*> {
53-
54-
val props = type.jvmErasure.declaredMemberProperties.filter { it.visibility == KVisibility.PUBLIC }
54+
val erasure = type.jvmErasure
55+
if (erasure.isSealed) {
56+
return Schema.OneSchemaOf(erasure.sealedSubclasses.map { get(it.starProjectedType).schema })
57+
}
58+
val props = erasure.declaredMemberProperties.filter { it.visibility == KVisibility.PUBLIC }
5559
val properties = props.associate {
5660
Pair(it.name, get(it.returnType).schema)
5761
}
@@ -65,4 +69,4 @@ open class SimpleSchemaRegistrar(val namer: SchemaNamer) : SchemaRegistrar {
6569
val type = type.arguments[1].type ?: getKType<String>()
6670
return Schema.SchemaMap(get(type).schema as Schema<Any>)
6771
}
68-
}
72+
}

src/main/kotlin/com/papsign/ktor/openapigen/openapi/Flows.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package com.papsign.ktor.openapigen.openapi
22

3+
import java.util.*
34
import kotlin.reflect.KProperty
45

5-
class Flows<T>: MutableMap<Flows.FlowType, Flows.Flow<T>> by HashMap()
6+
class Flows<T>: MutableMap<Flows.FlowType, Flows.Flow<T>> by EnumMap(FlowType::class.java)
67
where T : Enum<T>, T : Described {
78

89
private var implicit: Flow<T>? by this
@@ -116,4 +117,4 @@ class Flows<T>: MutableMap<Flows.FlowType, Flows.Flow<T>> by HashMap()
116117
}
117118
}
118119
}
119-
}
120+
}

src/main/kotlin/com/papsign/ktor/openapigen/route/path/auth/Functions.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package com.papsign.ktor.openapigen.route.path.auth
22

3-
import com.papsign.ktor.openapigen.interop.OAuth2Handler
43
import com.papsign.ktor.openapigen.modules.RouteOpenAPIModule
5-
import com.papsign.ktor.openapigen.openapi.Described
64
import com.papsign.ktor.openapigen.route.method
7-
import com.papsign.ktor.openapigen.route.path.normal.NormalOpenAPIRoute
85
import com.papsign.ktor.openapigen.route.preHandle
96
import com.papsign.ktor.openapigen.route.response.OpenAPIPipelineAuthContext
107
import io.ktor.http.HttpMethod
@@ -98,10 +95,3 @@ inline fun <reified P : Any, reified R : Any, A> OpenAPIAuthenticatedRoute<A>.h
9895
}
9996

10097
suspend fun <A> OpenAPIPipelineAuthContext<A, *>.principal() = authProvider.getAuth(pipeline)
101-
102-
103-
inline fun <A, T> NormalOpenAPIRoute.auth(handler: OAuth2Handler<A, T>, vararg scopes: T, crossinline fn: OpenAPIAuthenticatedRoute<A>.()->Unit) where T: Enum<T>, T: Described = auth(handler, scopes.asList(), fn)
104-
105-
inline fun <A, T> NormalOpenAPIRoute.auth(handler: OAuth2Handler<A, T>, scopes: List<T>, crossinline fn: OpenAPIAuthenticatedRoute<A>.()->Unit) where T: Enum<T>, T: Described {
106-
handler.auth(this, scopes).fn()
107-
}

src/test/kotlin/TestServer.kt

Lines changed: 44 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import com.fasterxml.jackson.annotation.JsonInclude
2+
import com.fasterxml.jackson.annotation.JsonSubTypes
3+
import com.fasterxml.jackson.annotation.JsonTypeInfo
4+
import com.fasterxml.jackson.annotation.JsonTypeName
25
import com.fasterxml.jackson.core.util.DefaultIndenter
36
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
47
import com.fasterxml.jackson.databind.DeserializationFeature
@@ -11,31 +14,23 @@ import com.papsign.ktor.openapigen.annotations.Path
1114
import com.papsign.ktor.openapigen.annotations.Request
1215
import com.papsign.ktor.openapigen.annotations.Response
1316
import com.papsign.ktor.openapigen.annotations.parameters.PathParam
14-
import com.papsign.ktor.openapigen.interop.OAuth2Handler
15-
import com.papsign.ktor.openapigen.interop.configure
1617
import com.papsign.ktor.openapigen.interop.withAPI
1718
import com.papsign.ktor.openapigen.openAPIGen
1819
import com.papsign.ktor.openapigen.openapi.Described
1920
import com.papsign.ktor.openapigen.openapi.Server
2021
import com.papsign.ktor.openapigen.route.apiRouting
2122
import com.papsign.ktor.openapigen.route.info
22-
import com.papsign.ktor.openapigen.route.path.auth.auth
23-
import com.papsign.ktor.openapigen.route.path.auth.get
24-
import com.papsign.ktor.openapigen.route.path.auth.post
25-
import com.papsign.ktor.openapigen.route.path.auth.principal
2623
import com.papsign.ktor.openapigen.route.path.normal.get
24+
import com.papsign.ktor.openapigen.route.path.normal.post
2725
import com.papsign.ktor.openapigen.route.response.respond
2826
import com.papsign.ktor.openapigen.route.route
2927
import com.papsign.ktor.openapigen.route.tag
3028
import io.ktor.application.application
3129
import io.ktor.application.call
3230
import io.ktor.application.install
33-
import io.ktor.auth.Authentication
34-
import io.ktor.auth.OAuthServerSettings
3531
import io.ktor.features.ContentNegotiation
3632
import io.ktor.features.StatusPages
3733
import io.ktor.features.origin
38-
import io.ktor.http.HttpMethod
3934
import io.ktor.http.HttpStatusCode
4035
import io.ktor.jackson.jackson
4136
import io.ktor.request.host
@@ -53,8 +48,6 @@ object TestServer {
5348

5449
class ProperException(msg: String, val id: String = "proper.exception") : Exception(msg)
5550

56-
lateinit var oauth: OAuth2Handler<APIPrincipal, Scopes>
57-
5851
@JvmStatic
5952
fun main(args: Array<String>) {
6053
embeddedServer(Netty, 8080, "localhost") {
@@ -82,9 +75,9 @@ object TestServer {
8275
install(ContentNegotiation) {
8376
jackson {
8477
enable(
85-
DeserializationFeature.WRAP_EXCEPTIONS,
86-
DeserializationFeature.USE_BIG_INTEGER_FOR_INTS,
87-
DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS
78+
DeserializationFeature.WRAP_EXCEPTIONS,
79+
DeserializationFeature.USE_BIG_INTEGER_FOR_INTS,
80+
DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS
8881
)
8982

9083
enable(SerializationFeature.WRAP_EXCEPTIONS, SerializationFeature.INDENT_OUTPUT)
@@ -117,35 +110,15 @@ object TestServer {
117110

118111
val scopes = Scopes.values().asList()
119112

120-
val googleOAuthProvider = OAuthServerSettings.OAuth2ServerSettings(
121-
name = "google",
122-
authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
123-
accessTokenUrl = "https://www.googleapis.com/oauth2/v3/token",
124-
requestMethod = HttpMethod.Post,
125-
126-
clientId = "<id>",
127-
clientSecret = "<secret>",
128-
defaultScopes = scopes.map { it.name }
129-
)
130-
131-
oauth = OAuth2Handler(googleOAuthProvider, scopes, scopes, scopes, scopes) { auth ->
132-
APIPrincipal(auth.tokenType, auth.accessToken)
133-
}
134-
135-
// auth interop
136-
install(Authentication) {
137-
configure(oauth)
138-
}
139-
140113
// serve OpenAPI and redirect from root
141114
routing {
142115
get("/openapi.json") {
143116
val host = Server(
144-
call.request.origin.scheme + "://" + call.request.host() + if (setOf(
145-
80,
146-
443
147-
).contains(call.request.port())
148-
) "" else ":${call.request.port()}"
117+
call.request.origin.scheme + "://" + call.request.host() + if (setOf(
118+
80,
119+
443
120+
).contains(call.request.port())
121+
) "" else ":${call.request.port()}"
149122
)
150123
application.openAPIGen.api.servers.add(0, host)
151124
call.respond(application.openAPIGen.api)
@@ -160,15 +133,25 @@ object TestServer {
160133
apiRouting {
161134

162135
get<StringParam, StringResponse>(
163-
info("String Param Endpoint", "This is a String Param Endpoint"),
164-
example = StringResponse("Hi")
136+
info("String Param Endpoint", "This is a String Param Endpoint"),
137+
example = StringResponse("Hi")
165138
) { params ->
166139
respond(StringResponse(params.a))
167140
}
168141

142+
route("sealed") {
143+
post<Unit, Base, Base>(
144+
info("Sealed class Endpoint", "This is a Sealed class Endpoint"),
145+
exampleRequest = Base.A("Hi"),
146+
exampleResponse = Base.A("Hi")
147+
) { params, base ->
148+
respond(base)
149+
}
150+
}
151+
169152
route("long").get<LongParam, LongResponse>(
170-
info("Long Param Endpoint", "This is a String Param Endpoint"),
171-
example = LongResponse(Long.MAX_VALUE)
153+
info("Long Param Endpoint", "This is a String Param Endpoint"),
154+
example = LongResponse(Long.MAX_VALUE)
172155
) { params ->
173156
respond(LongResponse(params.a))
174157
}
@@ -177,45 +160,21 @@ object TestServer {
177160
tag(TestServer.Tags.EXAMPLE) {
178161

179162
get<StringParam, StringResponse>(
180-
info("String Param Endpoint", "This is a String Param Endpoint"),
181-
example = StringResponse("Hi")
163+
info("String Param Endpoint", "This is a String Param Endpoint"),
164+
example = StringResponse("Hi")
182165
) { params ->
183166
respond(StringResponse(params.a))
184167
}
185168

186169
route("long").get<LongParam, LongResponse>(
187-
info("Long Param Endpoint", "This is a String Param Endpoint"),
188-
example = LongResponse(Long.MAX_VALUE)
170+
info("Long Param Endpoint", "This is a String Param Endpoint"),
171+
example = LongResponse(Long.MAX_VALUE)
189172
) { params ->
190173
respond(LongResponse(params.a))
191174
}
192175
}
193176

194-
}
195-
196-
tag(TestServer.Tags.EXAMPLE) {
197-
route("authenticated") {
198-
199-
auth(oauth) {
200-
201-
get<StringParam, StringResponse, APIPrincipal>(
202-
info(
203-
"Authenticated String Param Endpoint",
204-
"This is aa authenticated String Param Endpoint"
205-
),
206-
example = StringResponse("Hi")
207-
) { params ->
208-
val p = principal()
209-
respond(StringResponse(params.a + p.a + p.b))
210-
}
211-
212177

213-
post<Unit, StringUsable, StringUsable, APIPrincipal> { _, str ->
214-
respond(str)
215-
}
216-
217-
}
218-
}
219178
}
220179
}
221180
}.start(true)
@@ -238,12 +197,24 @@ object TestServer {
238197
@Response("A Long Response")
239198
data class LongResponse(val str: Long)
240199

200+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
201+
@JsonSubTypes(
202+
JsonSubTypes.Type(Base.A::class, name = "a"),
203+
JsonSubTypes.Type(Base.B::class, name = "b"),
204+
JsonSubTypes.Type(Base.C::class, name = "c")
205+
)
206+
sealed class Base {
207+
class A(val str: String) : Base()
208+
class B(val i: Int) : Base()
209+
class C(val l: Long) : Base()
210+
}
211+
241212

242-
enum class Tags(override val description: String): APITag {
213+
enum class Tags(override val description: String) : APITag {
243214
EXAMPLE("Wow this is a tag?!")
244215
}
245216

246-
enum class Scopes(override val description: String): Described {
217+
enum class Scopes(override val description: String) : Described {
247218
profile("Basic Profile scope"), email("Email scope")
248219
}
249220

0 commit comments

Comments
 (0)