@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Updates for Ktor 3.x support
|
||||||
|
- Remove deprecated `NotarizedLocations`
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.9.25" apply false
|
kotlin("jvm") version "2.0.21" apply false
|
||||||
kotlin("plugin.serialization") version "1.9.25" apply false
|
kotlin("plugin.serialization") version "2.0.21" apply false
|
||||||
id("io.bkbn.sourdough.library.jvm") version "0.12.2" apply false
|
id("io.bkbn.sourdough.library.jvm") version "0.12.2" apply false
|
||||||
id("io.bkbn.sourdough.application.jvm") version "0.12.2" apply false
|
id("io.bkbn.sourdough.application.jvm") version "0.12.2" apply false
|
||||||
id("io.bkbn.sourdough.root") version "0.12.2"
|
id("io.bkbn.sourdough.root") version "0.12.2"
|
||||||
|
@ -20,6 +20,7 @@ sourdoughLibrary {
|
|||||||
dependencies {
|
dependencies {
|
||||||
// VERSIONS
|
// VERSIONS
|
||||||
val kotestVersion: String by project
|
val kotestVersion: String by project
|
||||||
|
val kotlinSerializeVersion: String by project
|
||||||
val ktorVersion: String by project
|
val ktorVersion: String by project
|
||||||
val detektVersion: String by project
|
val detektVersion: String by project
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ dependencies {
|
|||||||
testFixturesApi("io.kotest:kotest-assertions-core-jvm:$kotestVersion")
|
testFixturesApi("io.kotest:kotest-assertions-core-jvm:$kotestVersion")
|
||||||
testFixturesApi("io.kotest:kotest-property-jvm:$kotestVersion")
|
testFixturesApi("io.kotest:kotest-property-jvm:$kotestVersion")
|
||||||
testFixturesApi("io.kotest:kotest-assertions-json-jvm:$kotestVersion")
|
testFixturesApi("io.kotest:kotest-assertions-json-jvm:$kotestVersion")
|
||||||
testFixturesApi("io.kotest:kotest-assertions-ktor-jvm:4.4.3")
|
testFixturesApi("io.kotest.extensions:kotest-assertions-ktor:2.0.0")
|
||||||
|
|
||||||
testFixturesApi("io.ktor:ktor-server-core:$ktorVersion")
|
testFixturesApi("io.ktor:ktor-server-core:$ktorVersion")
|
||||||
testFixturesApi("io.ktor:ktor-server-test-host:$ktorVersion")
|
testFixturesApi("io.ktor:ktor-server-test-host:$ktorVersion")
|
||||||
@ -57,7 +58,7 @@ dependencies {
|
|||||||
|
|
||||||
testFixturesApi("dev.forst:ktor-api-key:2.2.4")
|
testFixturesApi("dev.forst:ktor-api-key:2.2.4")
|
||||||
|
|
||||||
testFixturesApi("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
testFixturesApi("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializeVersion")
|
||||||
}
|
}
|
||||||
|
|
||||||
testing {
|
testing {
|
||||||
|
@ -6,7 +6,6 @@ import io.bkbn.kompendium.json.schema.SchemaConfigurator
|
|||||||
import io.bkbn.kompendium.json.schema.definition.JsonSchema
|
import io.bkbn.kompendium.json.schema.definition.JsonSchema
|
||||||
import io.bkbn.kompendium.json.schema.util.Helpers.getSimpleSlug
|
import io.bkbn.kompendium.json.schema.util.Helpers.getSimpleSlug
|
||||||
import io.bkbn.kompendium.oas.OpenApiSpec
|
import io.bkbn.kompendium.oas.OpenApiSpec
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.createApplicationPlugin
|
import io.ktor.server.application.createApplicationPlugin
|
||||||
import io.ktor.server.response.respond
|
import io.ktor.server.response.respond
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Routing
|
||||||
|
@ -78,7 +78,7 @@ object NotarizedRoute {
|
|||||||
|
|
||||||
fun Route.calculateRoutePath() = toString()
|
fun Route.calculateRoutePath() = toString()
|
||||||
.let {
|
.let {
|
||||||
application.environment.rootPath.takeIf { root -> root.isNotEmpty() }
|
application.rootPath.takeIf { root -> root.isNotEmpty() }
|
||||||
?.let { root ->
|
?.let { root ->
|
||||||
val sanitizedRoute = if (root.startsWith("/")) root else "/$root"
|
val sanitizedRoute = if (root.startsWith("/")) root else "/$root"
|
||||||
it.replace(sanitizedRoute, "")
|
it.replace(sanitizedRoute, "")
|
||||||
|
@ -18,6 +18,7 @@ import io.ktor.http.HttpMethod
|
|||||||
import io.ktor.server.application.install
|
import io.ktor.server.application.install
|
||||||
import io.ktor.server.auth.Authentication
|
import io.ktor.server.auth.Authentication
|
||||||
import io.ktor.server.auth.OAuthServerSettings
|
import io.ktor.server.auth.OAuthServerSettings
|
||||||
|
import io.ktor.server.auth.Principal
|
||||||
import io.ktor.server.auth.UserIdPrincipal
|
import io.ktor.server.auth.UserIdPrincipal
|
||||||
import io.ktor.server.auth.basic
|
import io.ktor.server.auth.basic
|
||||||
import io.ktor.server.auth.jwt.jwt
|
import io.ktor.server.auth.jwt.jwt
|
||||||
@ -92,14 +93,18 @@ class KompendiumAuthenticationTest : DescribeSpec({
|
|||||||
) { customAuthConfig() }
|
) { customAuthConfig() }
|
||||||
}
|
}
|
||||||
it("Can provide multiple authentication strategies") {
|
it("Can provide multiple authentication strategies") {
|
||||||
|
data class TestAppPrincipal(val key: String) : Principal
|
||||||
TestHelpers.openApiTestAllSerializers(
|
TestHelpers.openApiTestAllSerializers(
|
||||||
snapshotName = "T0047__multiple_auth_strategies.json",
|
snapshotName = "T0047__multiple_auth_strategies.json",
|
||||||
applicationSetup = {
|
applicationSetup = {
|
||||||
install(Authentication) {
|
install(Authentication) {
|
||||||
apiKey("api-key") {
|
apiKey("api-key") {
|
||||||
headerName = "X-API-KEY"
|
headerName = "X-API-KEY"
|
||||||
validate {
|
validate { key ->
|
||||||
UserIdPrincipal("Placeholder")
|
// api key library (dev.forst.ktor.apikey) is using the deprecated `Principal` class
|
||||||
|
key
|
||||||
|
.takeIf { it == "api-key" }
|
||||||
|
?.let { TestAppPrincipal(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jwt("jwt") {
|
jwt("jwt") {
|
||||||
|
@ -38,7 +38,6 @@ import io.bkbn.kompendium.oas.security.BasicAuth
|
|||||||
import io.bkbn.kompendium.oas.serialization.KompendiumSerializersModule
|
import io.bkbn.kompendium.oas.serialization.KompendiumSerializersModule
|
||||||
import io.kotest.core.spec.style.DescribeSpec
|
import io.kotest.core.spec.style.DescribeSpec
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.application.install
|
||||||
import io.ktor.server.auth.Authentication
|
import io.ktor.server.auth.Authentication
|
||||||
import io.ktor.server.auth.UserIdPrincipal
|
import io.ktor.server.auth.UserIdPrincipal
|
||||||
@ -182,13 +181,16 @@ class KompendiumTest : DescribeSpec({
|
|||||||
it("Can generate paths without application root-path") {
|
it("Can generate paths without application root-path") {
|
||||||
openApiTestAllSerializers(
|
openApiTestAllSerializers(
|
||||||
"T0054__app_with_rootpath.json",
|
"T0054__app_with_rootpath.json",
|
||||||
applicationEnvironmentBuilder = {
|
applicationSetup = {
|
||||||
rootPath = "/example"
|
rootPath = "/example"
|
||||||
},
|
},
|
||||||
specOverrides = {
|
specOverrides = {
|
||||||
copy(
|
copy(
|
||||||
servers = servers.map { it.copy(url = URI("${it.url}/example")) }.toMutableList()
|
servers = servers.map { it.copy(url = URI("${it.url}/example")) }.toMutableList()
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
serverConfigSetup = {
|
||||||
|
rootPath = "/example"
|
||||||
}
|
}
|
||||||
) { notarizedGet() }
|
) { notarizedGet() }
|
||||||
}
|
}
|
||||||
@ -202,12 +204,10 @@ class KompendiumTest : DescribeSpec({
|
|||||||
snapshotName = "T0072__custom_serialization_strategy.json",
|
snapshotName = "T0072__custom_serialization_strategy.json",
|
||||||
notarizedApplicationConfigOverrides = {
|
notarizedApplicationConfigOverrides = {
|
||||||
specRoute = { spec, routing ->
|
specRoute = { spec, routing ->
|
||||||
routing {
|
routing.route("/openapi.json") {
|
||||||
route("/openapi.json") {
|
get {
|
||||||
get {
|
call.response.headers.append("Content-Type", "application/json")
|
||||||
call.response.headers.append("Content-Type", "application/json")
|
call.respondText { customJsonEncoder.encodeToString(spec) }
|
||||||
call.respondText { customJsonEncoder.encodeToString(spec) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,11 @@ import io.bkbn.kompendium.core.util.TestModules.defaultPathSummary
|
|||||||
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
|
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
|
||||||
import io.bkbn.kompendium.core.util.TestModules.rootPath
|
import io.bkbn.kompendium.core.util.TestModules.rootPath
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.install
|
|
||||||
import io.ktor.server.auth.authenticate
|
import io.ktor.server.auth.authenticate
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.post
|
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
|
||||||
fun Routing.defaultAuthConfig() {
|
fun Route.defaultAuthConfig() {
|
||||||
authenticate("basic") {
|
authenticate("basic") {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
basicGetGenerator<TestResponse>()
|
basicGetGenerator<TestResponse>()
|
||||||
@ -23,7 +21,7 @@ fun Routing.defaultAuthConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.customAuthConfig() {
|
fun Route.customAuthConfig() {
|
||||||
authenticate("auth-oauth-google") {
|
authenticate("auth-oauth-google") {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
@ -44,7 +42,7 @@ fun Routing.customAuthConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.customScopesOnSiblingPathOperations() {
|
fun Route.customScopesOnSiblingPathOperations() {
|
||||||
authenticate("auth-oauth-google") {
|
authenticate("auth-oauth-google") {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
@ -81,7 +79,7 @@ fun Routing.customScopesOnSiblingPathOperations() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.multipleAuthStrategies() {
|
fun Route.multipleAuthStrategies() {
|
||||||
authenticate("jwt", "api-key") {
|
authenticate("jwt", "api-key") {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
basicGetGenerator<TestResponse>()
|
basicGetGenerator<TestResponse>()
|
||||||
|
@ -12,11 +12,10 @@ import io.bkbn.kompendium.enrichment.NumberEnrichment
|
|||||||
import io.bkbn.kompendium.enrichment.ObjectEnrichment
|
import io.bkbn.kompendium.enrichment.ObjectEnrichment
|
||||||
import io.bkbn.kompendium.enrichment.StringEnrichment
|
import io.bkbn.kompendium.enrichment.StringEnrichment
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.Routing
|
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
|
||||||
fun Routing.intConstraints() {
|
fun Route.intConstraints() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -43,7 +42,7 @@ fun Routing.intConstraints() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.doubleConstraints() {
|
fun Route.doubleConstraints() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -70,7 +69,7 @@ fun Routing.doubleConstraints() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.stringConstraints() {
|
fun Route.stringConstraints() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -96,7 +95,7 @@ fun Routing.stringConstraints() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.stringPatternConstraints() {
|
fun Route.stringPatternConstraints() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -121,7 +120,7 @@ fun Routing.stringPatternConstraints() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.stringContentEncodingConstraints() {
|
fun Route.stringContentEncodingConstraints() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -147,7 +146,7 @@ fun Routing.stringContentEncodingConstraints() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.arrayConstraints() {
|
fun Route.arrayConstraints() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
|
@ -3,8 +3,8 @@ package io.bkbn.kompendium.core.util
|
|||||||
import io.bkbn.kompendium.core.fixtures.SerialNameObject
|
import io.bkbn.kompendium.core.fixtures.SerialNameObject
|
||||||
import io.bkbn.kompendium.core.fixtures.TransientObject
|
import io.bkbn.kompendium.core.fixtures.TransientObject
|
||||||
import io.bkbn.kompendium.core.fixtures.UnbackedObject
|
import io.bkbn.kompendium.core.fixtures.UnbackedObject
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
|
|
||||||
fun Routing.ignoredFieldsResponse() = basicGetGenerator<TransientObject>()
|
fun Route.ignoredFieldsResponse() = basicGetGenerator<TransientObject>()
|
||||||
fun Routing.unbackedFieldsResponse() = basicGetGenerator<UnbackedObject>()
|
fun Route.unbackedFieldsResponse() = basicGetGenerator<UnbackedObject>()
|
||||||
fun Routing.customFieldNameResponse() = basicGetGenerator<SerialNameObject>()
|
fun Route.customFieldNameResponse() = basicGetGenerator<SerialNameObject>()
|
||||||
|
@ -3,9 +3,9 @@ package io.bkbn.kompendium.core.util
|
|||||||
import io.bkbn.kompendium.core.fixtures.TestResponse
|
import io.bkbn.kompendium.core.fixtures.TestResponse
|
||||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
|
|
||||||
fun Routing.defaultParameter() = basicGetGenerator<TestResponse>(
|
fun Route.defaultParameter() = basicGetGenerator<TestResponse>(
|
||||||
params = listOf(
|
params = listOf(
|
||||||
Parameter(
|
Parameter(
|
||||||
name = "id",
|
name = "id",
|
||||||
|
@ -16,11 +16,10 @@ import io.bkbn.kompendium.enrichment.NumberEnrichment
|
|||||||
import io.bkbn.kompendium.enrichment.ObjectEnrichment
|
import io.bkbn.kompendium.enrichment.ObjectEnrichment
|
||||||
import io.bkbn.kompendium.enrichment.StringEnrichment
|
import io.bkbn.kompendium.enrichment.StringEnrichment
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.Routing
|
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
|
||||||
fun Routing.enrichedSimpleResponse() {
|
fun Route.enrichedSimpleResponse() {
|
||||||
route("/enriched") {
|
route("/enriched") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -44,7 +43,7 @@ fun Routing.enrichedSimpleResponse() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.enrichedSimpleRequest() {
|
fun Route.enrichedSimpleRequest() {
|
||||||
route("/example") {
|
route("/example") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = TestModules.defaultParams
|
parameters = TestModules.defaultParams
|
||||||
@ -78,7 +77,7 @@ fun Routing.enrichedSimpleRequest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.enrichedNestedCollection() {
|
fun Route.enrichedNestedCollection() {
|
||||||
route("/example") {
|
route("/example") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = TestModules.defaultParams
|
parameters = TestModules.defaultParams
|
||||||
@ -114,7 +113,7 @@ fun Routing.enrichedNestedCollection() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.enrichedTopLevelCollection() {
|
fun Route.enrichedTopLevelCollection() {
|
||||||
route("/example") {
|
route("/example") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = TestModules.defaultParams
|
parameters = TestModules.defaultParams
|
||||||
@ -150,7 +149,7 @@ fun Routing.enrichedTopLevelCollection() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.enrichedComplexGenericType() {
|
fun Route.enrichedComplexGenericType() {
|
||||||
route("/example") {
|
route("/example") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = TestModules.defaultParams
|
parameters = TestModules.defaultParams
|
||||||
@ -193,7 +192,7 @@ fun Routing.enrichedComplexGenericType() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.enrichedGenericResponse() {
|
fun Route.enrichedGenericResponse() {
|
||||||
route("/example") {
|
route("/example") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -228,7 +227,7 @@ fun Routing.enrichedGenericResponse() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.enrichedMap() {
|
fun Route.enrichedMap() {
|
||||||
route("/example") {
|
route("/example") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
|
@ -3,10 +3,10 @@ package io.bkbn.kompendium.core.util
|
|||||||
import io.bkbn.kompendium.core.fixtures.TestResponse
|
import io.bkbn.kompendium.core.fixtures.TestResponse
|
||||||
import io.bkbn.kompendium.core.util.TestModules.defaultPath
|
import io.bkbn.kompendium.core.util.TestModules.defaultPath
|
||||||
import io.ktor.server.auth.authenticate
|
import io.ktor.server.auth.authenticate
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
|
||||||
fun Routing.samePathSameMethod() {
|
fun Route.samePathSameMethod() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
basicGetGenerator<TestResponse>()
|
basicGetGenerator<TestResponse>()
|
||||||
authenticate("basic") {
|
authenticate("basic") {
|
||||||
|
@ -14,11 +14,10 @@ import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
|||||||
import io.bkbn.kompendium.oas.payload.MediaType
|
import io.bkbn.kompendium.oas.payload.MediaType
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.Routing
|
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
|
||||||
fun Routing.reqRespExamples() {
|
fun Route.reqRespExamples() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
post = PostInfo.builder {
|
post = PostInfo.builder {
|
||||||
@ -44,7 +43,7 @@ fun Routing.reqRespExamples() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.exampleParams() = basicGetGenerator<TestResponse>(
|
fun Route.exampleParams() = basicGetGenerator<TestResponse>(
|
||||||
params = listOf(
|
params = listOf(
|
||||||
Parameter(
|
Parameter(
|
||||||
name = "id",
|
name = "id",
|
||||||
@ -57,7 +56,7 @@ fun Routing.exampleParams() = basicGetGenerator<TestResponse>(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Routing.optionalReqExample() {
|
fun Route.optionalReqExample() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
post = PostInfo.builder {
|
post = PostInfo.builder {
|
||||||
@ -84,7 +83,7 @@ fun Routing.optionalReqExample() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.exampleSummaryAndDescription() {
|
fun Route.exampleSummaryAndDescription() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
post = PostInfo.builder {
|
post = PostInfo.builder {
|
||||||
|
@ -11,11 +11,10 @@ import io.bkbn.kompendium.core.util.TestModules.defaultPathSummary
|
|||||||
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
|
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
|
||||||
import io.bkbn.kompendium.core.util.TestModules.rootPath
|
import io.bkbn.kompendium.core.util.TestModules.rootPath
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.Routing
|
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
|
||||||
fun Routing.singleException() {
|
fun Route.singleException() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -36,7 +35,7 @@ fun Routing.singleException() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.multipleExceptions() {
|
fun Route.multipleExceptions() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -62,7 +61,7 @@ fun Routing.multipleExceptions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.polymorphicException() {
|
fun Route.polymorphicException() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
@ -83,7 +82,7 @@ fun Routing.polymorphicException() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.genericException() {
|
fun Route.genericException() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
get = GetInfo.builder {
|
get = GetInfo.builder {
|
||||||
|
@ -21,17 +21,16 @@ import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
|
|||||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.install
|
|
||||||
import io.ktor.server.auth.authenticate
|
import io.ktor.server.auth.authenticate
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
|
||||||
fun Routing.withOperationId() = basicGetGenerator<TestResponse>(operationId = "getThisDude")
|
fun Route.withOperationId() = basicGetGenerator<TestResponse>(operationId = "getThisDude")
|
||||||
fun Routing.nullableNestedObject() = basicGetGenerator<ProfileUpdateRequest>()
|
fun Route.nullableNestedObject() = basicGetGenerator<ProfileUpdateRequest>()
|
||||||
fun Routing.nullableEnumField() = basicGetGenerator<NullableEnum>()
|
fun Route.nullableEnumField() = basicGetGenerator<NullableEnum>()
|
||||||
fun Routing.nullableReference() = basicGetGenerator<ManyThings>()
|
fun Route.nullableReference() = basicGetGenerator<ManyThings>()
|
||||||
fun Routing.dateTimeString() = basicGetGenerator<DateTimeString>()
|
fun Route.dateTimeString() = basicGetGenerator<DateTimeString>()
|
||||||
fun Routing.headerParameter() = basicGetGenerator<TestResponse>(
|
fun Route.headerParameter() = basicGetGenerator<TestResponse>(
|
||||||
params = listOf(
|
params = listOf(
|
||||||
Parameter(
|
Parameter(
|
||||||
name = "X-User-Email",
|
name = "X-User-Email",
|
||||||
@ -42,10 +41,10 @@ fun Routing.headerParameter() = basicGetGenerator<TestResponse>(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Routing.nestedTypeName() = basicGetGenerator<Nested.Response>()
|
fun Route.nestedTypeName() = basicGetGenerator<Nested.Response>()
|
||||||
fun Routing.topLevelNullable() = basicGetGenerator<TestResponse?>()
|
fun Route.topLevelNullable() = basicGetGenerator<TestResponse?>()
|
||||||
fun Routing.simpleRecursive() = basicGetGenerator<ColumnSchema>()
|
fun Route.simpleRecursive() = basicGetGenerator<ColumnSchema>()
|
||||||
fun Routing.samePathDifferentMethodsAndAuth() {
|
fun Route.samePathDifferentMethodsAndAuth() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
|
@ -26,11 +26,9 @@ import io.bkbn.kompendium.oas.payload.Header
|
|||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.ktor.http.HttpHeaders
|
import io.ktor.http.HttpHeaders
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
|
||||||
import io.ktor.server.response.respond
|
import io.ktor.server.response.respond
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.delete
|
import io.ktor.server.routing.delete
|
||||||
import io.ktor.server.routing.get
|
import io.ktor.server.routing.get
|
||||||
import io.ktor.server.routing.head
|
import io.ktor.server.routing.head
|
||||||
@ -40,7 +38,7 @@ import io.ktor.server.routing.post
|
|||||||
import io.ktor.server.routing.put
|
import io.ktor.server.routing.put
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
|
||||||
fun Routing.notarizedGet() {
|
fun Route.notarizedGet() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -60,7 +58,7 @@ fun Routing.notarizedGet() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.responseHeaders() {
|
fun Route.responseHeaders() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -92,7 +90,7 @@ fun Routing.responseHeaders() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.notarizedPost() {
|
fun Route.notarizedPost() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -116,7 +114,7 @@ fun Routing.notarizedPost() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.notarizedPut() {
|
fun Route.notarizedPut() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -140,7 +138,7 @@ fun Routing.notarizedPut() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.notarizedDelete() {
|
fun Route.notarizedDelete() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -160,7 +158,7 @@ fun Routing.notarizedDelete() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.notarizedPatch() {
|
fun Route.notarizedPatch() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -184,7 +182,7 @@ fun Routing.notarizedPatch() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.notarizedHead() {
|
fun Route.notarizedHead() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -205,7 +203,7 @@ fun Routing.notarizedHead() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.notarizedOptions() {
|
fun Route.notarizedOptions() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -225,7 +223,7 @@ fun Routing.notarizedOptions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.complexRequest() {
|
fun Route.complexRequest() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
put = PutInfo.builder {
|
put = PutInfo.builder {
|
||||||
@ -248,7 +246,7 @@ fun Routing.complexRequest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.primitives() {
|
fun Route.primitives() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
put = PutInfo.builder {
|
put = PutInfo.builder {
|
||||||
@ -268,7 +266,7 @@ fun Routing.primitives() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.returnsList() {
|
fun Route.returnsList() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -285,7 +283,7 @@ fun Routing.returnsList() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.returnsEnumList() {
|
fun Route.returnsEnumList() {
|
||||||
route(defaultPath) {
|
route(defaultPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = defaultParams
|
parameters = defaultParams
|
||||||
@ -302,7 +300,7 @@ fun Routing.returnsEnumList() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.nonRequiredParams() {
|
fun Route.nonRequiredParams() {
|
||||||
route("/optional") {
|
route("/optional") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = listOf(
|
parameters = listOf(
|
||||||
@ -331,7 +329,7 @@ fun Routing.nonRequiredParams() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.overrideMediaTypes() {
|
fun Route.overrideMediaTypes() {
|
||||||
route("/media_types") {
|
route("/media_types") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
put = PutInfo.builder {
|
put = PutInfo.builder {
|
||||||
@ -353,7 +351,7 @@ fun Routing.overrideMediaTypes() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.postNoReqBody() {
|
fun Route.postNoReqBody() {
|
||||||
route("/no_req_body") {
|
route("/no_req_body") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
post = PostInfo.builder {
|
post = PostInfo.builder {
|
||||||
@ -369,7 +367,7 @@ fun Routing.postNoReqBody() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.fieldOutsideConstructor() {
|
fun Route.fieldOutsideConstructor() {
|
||||||
route("/field_outside_constructor") {
|
route("/field_outside_constructor") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
post = PostInfo.builder {
|
post = PostInfo.builder {
|
||||||
|
@ -10,17 +10,17 @@ import io.bkbn.kompendium.core.fixtures.Gibbity
|
|||||||
import io.bkbn.kompendium.core.fixtures.Gizmo
|
import io.bkbn.kompendium.core.fixtures.Gizmo
|
||||||
import io.bkbn.kompendium.core.fixtures.MultiNestedGenerics
|
import io.bkbn.kompendium.core.fixtures.MultiNestedGenerics
|
||||||
import io.bkbn.kompendium.core.fixtures.Page
|
import io.bkbn.kompendium.core.fixtures.Page
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
|
|
||||||
fun Routing.polymorphicResponse() = basicGetGenerator<FlibbityGibbit>()
|
fun Route.polymorphicResponse() = basicGetGenerator<FlibbityGibbit>()
|
||||||
fun Routing.polymorphicCollectionResponse() = basicGetGenerator<List<FlibbityGibbit>>()
|
fun Route.polymorphicCollectionResponse() = basicGetGenerator<List<FlibbityGibbit>>()
|
||||||
fun Routing.polymorphicMapResponse() = basicGetGenerator<Map<String, FlibbityGibbit>>()
|
fun Route.polymorphicMapResponse() = basicGetGenerator<Map<String, FlibbityGibbit>>()
|
||||||
fun Routing.simpleGenericResponse() = basicGetGenerator<Gibbity<String>>()
|
fun Route.simpleGenericResponse() = basicGetGenerator<Gibbity<String>>()
|
||||||
fun Routing.gnarlyGenericResponse() = basicGetGenerator<Foosy<Barzo<Int>, String>>()
|
fun Route.gnarlyGenericResponse() = basicGetGenerator<Foosy<Barzo<Int>, String>>()
|
||||||
fun Routing.nestedGenericResponse() = basicGetGenerator<Gibbity<Map<String, String>>>()
|
fun Route.nestedGenericResponse() = basicGetGenerator<Gibbity<Map<String, String>>>()
|
||||||
fun Routing.genericPolymorphicResponse() = basicGetGenerator<Flibbity<Double>>()
|
fun Route.genericPolymorphicResponse() = basicGetGenerator<Flibbity<Double>>()
|
||||||
fun Routing.genericPolymorphicResponseMultipleImpls() = basicGetGenerator<Flibbity<FlibbityGibbit>>()
|
fun Route.genericPolymorphicResponseMultipleImpls() = basicGetGenerator<Flibbity<FlibbityGibbit>>()
|
||||||
fun Routing.nestedGenericCollection() = basicGetGenerator<Page<Int>>()
|
fun Route.nestedGenericCollection() = basicGetGenerator<Page<Int>>()
|
||||||
fun Routing.nestedGenericMultipleParamsCollection() = basicGetGenerator<MultiNestedGenerics<String, ComplexRequest>>()
|
fun Route.nestedGenericMultipleParamsCollection() = basicGetGenerator<MultiNestedGenerics<String, ComplexRequest>>()
|
||||||
fun Routing.overrideSealedTypeIdentifier() = basicGetGenerator<ChillaxificationMaximization>()
|
fun Route.overrideSealedTypeIdentifier() = basicGetGenerator<ChillaxificationMaximization>()
|
||||||
fun Routing.subtypeNotCompleteSetOfParentProperties() = basicGetGenerator<Gizmo>()
|
fun Route.subtypeNotCompleteSetOfParentProperties() = basicGetGenerator<Gizmo>()
|
||||||
|
@ -5,9 +5,9 @@ import io.bkbn.kompendium.core.fixtures.NullableField
|
|||||||
import io.bkbn.kompendium.core.fixtures.TestResponse
|
import io.bkbn.kompendium.core.fixtures.TestResponse
|
||||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
|
|
||||||
fun Routing.requiredParams() = basicGetGenerator<TestResponse>(
|
fun Route.requiredParams() = basicGetGenerator<TestResponse>(
|
||||||
params = listOf(
|
params = listOf(
|
||||||
Parameter(
|
Parameter(
|
||||||
name = "id",
|
name = "id",
|
||||||
@ -17,7 +17,7 @@ fun Routing.requiredParams() = basicGetGenerator<TestResponse>(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Routing.nonRequiredParam() = basicGetGenerator<TestResponse>(
|
fun Route.nonRequiredParam() = basicGetGenerator<TestResponse>(
|
||||||
params = listOf(
|
params = listOf(
|
||||||
Parameter(
|
Parameter(
|
||||||
name = "id",
|
name = "id",
|
||||||
@ -28,5 +28,5 @@ fun Routing.nonRequiredParam() = basicGetGenerator<TestResponse>(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Routing.defaultField() = basicGetGenerator<DefaultField>()
|
fun Route.defaultField() = basicGetGenerator<DefaultField>()
|
||||||
fun Routing.nullableField() = basicGetGenerator<NullableField>()
|
fun Route.nullableField() = basicGetGenerator<NullableField>()
|
||||||
|
@ -11,12 +11,11 @@ import io.bkbn.kompendium.core.util.TestModules.rootPath
|
|||||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.Routing
|
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
import io.ktor.server.routing.param
|
import io.ktor.server.routing.param
|
||||||
|
|
||||||
fun Routing.simplePathParsing() {
|
fun Route.simplePathParsing() {
|
||||||
route("/this") {
|
route("/this") {
|
||||||
route("/is") {
|
route("/is") {
|
||||||
route("/a") {
|
route("/a") {
|
||||||
@ -49,7 +48,7 @@ fun Routing.simplePathParsing() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.rootRoute() {
|
fun Route.rootRoute() {
|
||||||
route(rootPath) {
|
route(rootPath) {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
parameters = listOf(defaultParams.last())
|
parameters = listOf(defaultParams.last())
|
||||||
@ -66,7 +65,7 @@ fun Routing.rootRoute() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.nestedUnderRoot() {
|
fun Route.nestedUnderRoot() {
|
||||||
route("/") {
|
route("/") {
|
||||||
route("/testerino") {
|
route("/testerino") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
@ -84,7 +83,7 @@ fun Routing.nestedUnderRoot() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.trailingSlash() {
|
fun Route.trailingSlash() {
|
||||||
route("/test") {
|
route("/test") {
|
||||||
route("/") {
|
route("/") {
|
||||||
install(NotarizedRoute()) {
|
install(NotarizedRoute()) {
|
||||||
@ -102,7 +101,7 @@ fun Routing.trailingSlash() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Routing.paramWrapper() {
|
fun Route.paramWrapper() {
|
||||||
route("/test") {
|
route("/test") {
|
||||||
param("a") {
|
param("a") {
|
||||||
param("b") {
|
param("b") {
|
||||||
|
@ -9,7 +9,6 @@ import io.bkbn.kompendium.core.util.TestModules.rootPath
|
|||||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.install
|
|
||||||
import io.ktor.server.routing.Route
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Routing
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
|
@ -17,10 +17,11 @@ import io.ktor.client.statement.bodyAsText
|
|||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import io.ktor.server.application.Application
|
import io.ktor.server.application.Application
|
||||||
import io.ktor.server.engine.ApplicationEngineEnvironmentBuilder
|
import io.ktor.server.application.ServerConfigBuilder
|
||||||
|
import io.ktor.server.engine.ApplicationEnvironmentBuilder
|
||||||
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
|
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
|
||||||
import io.ktor.server.plugins.contentnegotiation.ContentNegotiationConfig
|
import io.ktor.server.plugins.contentnegotiation.ContentNegotiationConfig
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.testing.ApplicationTestBuilder
|
import io.ktor.server.testing.ApplicationTestBuilder
|
||||||
import io.ktor.server.testing.testApplication
|
import io.ktor.server.testing.testApplication
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -59,7 +60,7 @@ object TestHelpers {
|
|||||||
customTypes: Map<KType, JsonSchema> = emptyMap(),
|
customTypes: Map<KType, JsonSchema> = emptyMap(),
|
||||||
applicationSetup: Application.() -> Unit = { },
|
applicationSetup: Application.() -> Unit = { },
|
||||||
specOverrides: OpenApiSpec.() -> OpenApiSpec = { this },
|
specOverrides: OpenApiSpec.() -> OpenApiSpec = { this },
|
||||||
applicationEnvironmentBuilder: ApplicationEngineEnvironmentBuilder.() -> Unit = {},
|
applicationEnvironmentBuilder: ApplicationEnvironmentBuilder.() -> Unit = {},
|
||||||
notarizedApplicationConfigOverrides: NotarizedApplication.Config.() -> Unit = {},
|
notarizedApplicationConfigOverrides: NotarizedApplication.Config.() -> Unit = {},
|
||||||
contentNegotiation: ContentNegotiationConfig.() -> Unit = {
|
contentNegotiation: ContentNegotiationConfig.() -> Unit = {
|
||||||
json(Json {
|
json(Json {
|
||||||
@ -68,7 +69,9 @@ object TestHelpers {
|
|||||||
serializersModule = KompendiumSerializersModule.module
|
serializersModule = KompendiumSerializersModule.module
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
routeUnderTest: Routing.() -> Unit
|
|
||||||
|
serverConfigSetup: ServerConfigBuilder.() -> Unit = { },
|
||||||
|
routeUnderTest: Route.() -> Unit
|
||||||
) {
|
) {
|
||||||
openApiTest(
|
openApiTest(
|
||||||
snapshotName,
|
snapshotName,
|
||||||
@ -78,19 +81,21 @@ object TestHelpers {
|
|||||||
customTypes,
|
customTypes,
|
||||||
notarizedApplicationConfigOverrides,
|
notarizedApplicationConfigOverrides,
|
||||||
contentNegotiation,
|
contentNegotiation,
|
||||||
applicationEnvironmentBuilder
|
applicationEnvironmentBuilder,
|
||||||
|
serverConfigSetup
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openApiTest(
|
private fun openApiTest(
|
||||||
snapshotName: String,
|
snapshotName: String,
|
||||||
routeUnderTest: Routing.() -> Unit,
|
routeUnderTest: Route.() -> Unit,
|
||||||
applicationSetup: Application.() -> Unit,
|
applicationSetup: Application.() -> Unit,
|
||||||
specOverrides: OpenApiSpec.() -> OpenApiSpec,
|
specOverrides: OpenApiSpec.() -> OpenApiSpec,
|
||||||
typeOverrides: Map<KType, JsonSchema> = emptyMap(),
|
typeOverrides: Map<KType, JsonSchema> = emptyMap(),
|
||||||
notarizedApplicationConfigOverrides: NotarizedApplication.Config.() -> Unit,
|
notarizedApplicationConfigOverrides: NotarizedApplication.Config.() -> Unit,
|
||||||
contentNegotiation: ContentNegotiationConfig.() -> Unit,
|
contentNegotiation: ContentNegotiationConfig.() -> Unit,
|
||||||
applicationBuilder: ApplicationEngineEnvironmentBuilder.() -> Unit
|
applicationBuilder: ApplicationEnvironmentBuilder.() -> Unit,
|
||||||
|
serverConfigSetup: ServerConfigBuilder.() -> Unit
|
||||||
) = testApplication {
|
) = testApplication {
|
||||||
environment(applicationBuilder)
|
environment(applicationBuilder)
|
||||||
install(NotarizedApplication()) {
|
install(NotarizedApplication()) {
|
||||||
@ -103,12 +108,14 @@ object TestHelpers {
|
|||||||
contentNegotiation()
|
contentNegotiation()
|
||||||
}
|
}
|
||||||
application(applicationSetup)
|
application(applicationSetup)
|
||||||
|
serverConfig(serverConfigSetup)
|
||||||
routing {
|
routing {
|
||||||
swagger()
|
swagger()
|
||||||
redoc()
|
redoc()
|
||||||
routeUnderTest()
|
routeUnderTest()
|
||||||
}
|
}
|
||||||
val root = ApplicationEngineEnvironmentBuilder().apply(applicationBuilder).rootPath
|
|
||||||
|
val root = ServerConfigBuilder(ApplicationEnvironmentBuilder().apply(applicationBuilder).build()).apply(serverConfigSetup).rootPath
|
||||||
compareOpenAPISpec(root, snapshotName)
|
compareOpenAPISpec(root, snapshotName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
* [Plugins](plugins/index.md)
|
* [Plugins](plugins/index.md)
|
||||||
* [Notarized Application](plugins/notarized_application.md)
|
* [Notarized Application](plugins/notarized_application.md)
|
||||||
* [Notarized Route](plugins/notarized_route.md)
|
* [Notarized Route](plugins/notarized_route.md)
|
||||||
* [Notarized Locations](plugins/notarized_locations.md)
|
|
||||||
* [Notarized Resources](plugins/notarized_resources.md)
|
* [Notarized Resources](plugins/notarized_resources.md)
|
||||||
* [Concepts](concepts/index.md)
|
* [Concepts](concepts/index.md)
|
||||||
* [Enrichment](concepts/enrichment.md)
|
* [Enrichment](concepts/enrichment.md)
|
||||||
|
@ -12,7 +12,6 @@ At the moment, the following playground applications are
|
|||||||
| Gson | Serialization using Gson instead of the default Kotlinx |
|
| Gson | Serialization using Gson instead of the default Kotlinx |
|
||||||
| Hidden Docs | Place your generated documentation behind authorization |
|
| Hidden Docs | Place your generated documentation behind authorization |
|
||||||
| Jackson | Serialization using Jackson instead of the default KotlinX |
|
| Jackson | Serialization using Jackson instead of the default KotlinX |
|
||||||
| Locations | Using the Ktor Locations API to define routes |
|
|
||||||
| Resources | Using the Ktor Resources API to define routes |
|
| Resources | Using the Ktor Resources API to define routes |
|
||||||
|
|
||||||
You can find all of the playground
|
You can find all of the playground
|
||||||
|
@ -7,5 +7,5 @@ From there, a `NotarizedRoute` plugin is attached to each route you wish to docu
|
|||||||
be an iterative process. Each route you notarize will be picked up and injected into the OpenAPI spec that Kompendium
|
be an iterative process. Each route you notarize will be picked up and injected into the OpenAPI spec that Kompendium
|
||||||
generates for you.
|
generates for you.
|
||||||
|
|
||||||
Finally, there is the `NotarizedLocations` plugin that allows you to leverage and document your usage of the
|
Finally, there is the `NotarizedResources` plugin that allows you to leverage and document your usage of the
|
||||||
Ktor [Locations](https://ktor.io/docs/locations.html) API.
|
Ktor [Resources](https://ktor.io/docs/server-resources.html) API.
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
The Ktor Locations API is an experimental API that allows users to add increased type safety to their defined routes.
|
|
||||||
|
|
||||||
You can read more about it [here](https://ktor.io/docs/locations.html).
|
|
||||||
|
|
||||||
Kompendium supports Locations through an ancillary module `kompendium-locations`
|
|
||||||
|
|
||||||
## Adding the Artifact
|
|
||||||
|
|
||||||
Prior to documenting your locations, you will need to add the artifact to your gradle build file.
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
dependencies {
|
|
||||||
implementation("io.bkbn:kompendium-locations:latest.release")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installing Plugin
|
|
||||||
|
|
||||||
Once you have installed the dependency, you can install the plugin. The `NotarizedLocations` plugin is an _application_
|
|
||||||
level plugin, and **must** be install after both the `NotarizedApplication` plugin and the Ktor `Locations` plugin.
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
private fun Application.mainModule() {
|
|
||||||
install(Locations)
|
|
||||||
install(NotarizedApplication()) {
|
|
||||||
spec = baseSpec
|
|
||||||
}
|
|
||||||
install(NotarizedLocations()) {
|
|
||||||
locations = mapOf(
|
|
||||||
Listing::class to NotarizedLocations.LocationMetadata(
|
|
||||||
parameters = listOf(
|
|
||||||
Parameter(
|
|
||||||
name = "name",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.STRING
|
|
||||||
),
|
|
||||||
Parameter(
|
|
||||||
name = "page",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.INT
|
|
||||||
)
|
|
||||||
),
|
|
||||||
get = GetInfo.builder {
|
|
||||||
summary("Get user by id")
|
|
||||||
description("A very neat endpoint!")
|
|
||||||
response {
|
|
||||||
responseCode(HttpStatusCode.OK)
|
|
||||||
responseType<ExampleResponse>()
|
|
||||||
description("Will return whether or not the user is real 😱")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here, the `locations` property is a map of `KClass<*>` to metadata describing that locations metadata. This
|
|
||||||
metadata is functionally identical to how a standard `NotarizedRoute` is defined.
|
|
||||||
|
|
||||||
> ⚠️ If you try to map a class that is not annotated with the ktor `@Location` annotation, you will get a runtime
|
|
||||||
> exception!
|
|
@ -12,6 +12,8 @@ org.gradle.jvmargs=-Xmx2000m
|
|||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
ktorVersion=2.3.12
|
kotlinVersion=2.0.21
|
||||||
kotestVersion=5.9.1
|
kotlinSerializeVersion=1.7.+
|
||||||
|
ktorVersion=3.0.0
|
||||||
|
kotestVersion=6.0.0.M1
|
||||||
detektVersion=1.23.7
|
detektVersion=1.23.7
|
||||||
|
@ -19,12 +19,14 @@ sourdoughLibrary {
|
|||||||
dependencies {
|
dependencies {
|
||||||
// Versions
|
// Versions
|
||||||
val detektVersion: String by project
|
val detektVersion: String by project
|
||||||
|
val kotlinVersion: String by project
|
||||||
|
val kotlinSerializeVersion: String by project
|
||||||
|
|
||||||
// Kompendium
|
// Kompendium
|
||||||
api(projects.kompendiumEnrichment)
|
api(projects.kompendiumEnrichment)
|
||||||
|
|
||||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.25")
|
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializeVersion")
|
||||||
|
|
||||||
// Formatting
|
// Formatting
|
||||||
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
plugins {
|
|
||||||
kotlin("jvm")
|
|
||||||
id("io.bkbn.sourdough.library.jvm")
|
|
||||||
id("io.gitlab.arturbosch.detekt")
|
|
||||||
id("com.adarshr.test-logger")
|
|
||||||
id("maven-publish")
|
|
||||||
id("java-library")
|
|
||||||
id("signing")
|
|
||||||
id("org.jetbrains.kotlinx.kover")
|
|
||||||
}
|
|
||||||
|
|
||||||
sourdoughLibrary {
|
|
||||||
libraryName.set("Kompendium Locations")
|
|
||||||
libraryDescription.set("Supplemental library for Kompendium offering support for Ktor's Location API")
|
|
||||||
compilerArgs.set(listOf("-opt-in=kotlin.RequiresOptIn"))
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// Versions
|
|
||||||
val detektVersion: String by project
|
|
||||||
|
|
||||||
// IMPLEMENTATION
|
|
||||||
|
|
||||||
implementation(projects.kompendiumCore)
|
|
||||||
implementation("io.ktor:ktor-server-core:2.3.12")
|
|
||||||
implementation("io.ktor:ktor-server-locations:2.3.12")
|
|
||||||
|
|
||||||
// TESTING
|
|
||||||
|
|
||||||
testImplementation(testFixtures(projects.kompendiumCore))
|
|
||||||
|
|
||||||
// Formatting
|
|
||||||
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
|
||||||
}
|
|
||||||
|
|
||||||
testing {
|
|
||||||
suites {
|
|
||||||
named("test", JvmTestSuite::class) {
|
|
||||||
useJUnitJupiter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
package io.bkbn.kompendium.locations
|
|
||||||
|
|
||||||
import io.bkbn.kompendium.core.attribute.KompendiumAttributes
|
|
||||||
import io.bkbn.kompendium.core.metadata.DeleteInfo
|
|
||||||
import io.bkbn.kompendium.core.metadata.GetInfo
|
|
||||||
import io.bkbn.kompendium.core.metadata.HeadInfo
|
|
||||||
import io.bkbn.kompendium.core.metadata.OptionsInfo
|
|
||||||
import io.bkbn.kompendium.core.metadata.PatchInfo
|
|
||||||
import io.bkbn.kompendium.core.metadata.PostInfo
|
|
||||||
import io.bkbn.kompendium.core.metadata.PutInfo
|
|
||||||
import io.bkbn.kompendium.core.util.Helpers.addToSpec
|
|
||||||
import io.bkbn.kompendium.core.util.SpecConfig
|
|
||||||
import io.bkbn.kompendium.oas.path.Path
|
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
|
||||||
import io.ktor.server.application.createApplicationPlugin
|
|
||||||
import io.ktor.server.locations.KtorExperimentalLocationsAPI
|
|
||||||
import io.ktor.server.locations.Location
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
import kotlin.reflect.full.findAnnotation
|
|
||||||
import kotlin.reflect.full.hasAnnotation
|
|
||||||
import kotlin.reflect.full.memberProperties
|
|
||||||
|
|
||||||
@Deprecated(
|
|
||||||
message = "This functionality is deprecated and will be removed in the future. " +
|
|
||||||
"Use 'ktor-server-resources' with 'kompendium-resources' plugin instead.",
|
|
||||||
level = DeprecationLevel.WARNING
|
|
||||||
)
|
|
||||||
object NotarizedLocations {
|
|
||||||
|
|
||||||
data class LocationMetadata(
|
|
||||||
override var tags: Set<String> = emptySet(),
|
|
||||||
override var parameters: List<Parameter> = emptyList(),
|
|
||||||
override var get: GetInfo? = null,
|
|
||||||
override var post: PostInfo? = null,
|
|
||||||
override var put: PutInfo? = null,
|
|
||||||
override var delete: DeleteInfo? = null,
|
|
||||||
override var patch: PatchInfo? = null,
|
|
||||||
override var head: HeadInfo? = null,
|
|
||||||
override var options: OptionsInfo? = null,
|
|
||||||
override var security: Map<String, List<String>>? = null,
|
|
||||||
) : SpecConfig
|
|
||||||
|
|
||||||
class Config {
|
|
||||||
lateinit var locations: Map<KClass<*>, LocationMetadata>
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun invoke() = createApplicationPlugin(
|
|
||||||
name = "NotarizedLocations",
|
|
||||||
createConfiguration = ::Config
|
|
||||||
) {
|
|
||||||
val spec = application.attributes[KompendiumAttributes.openApiSpec]
|
|
||||||
val serializableReader = application.attributes[KompendiumAttributes.schemaConfigurator]
|
|
||||||
pluginConfig.locations.forEach { (k, v) ->
|
|
||||||
val location = k.getLocationFromClass()
|
|
||||||
val path = spec.paths[location] ?: Path()
|
|
||||||
path.parameters = path.parameters?.plus(v.parameters) ?: v.parameters
|
|
||||||
v.get?.addToSpec(path, spec, v, serializableReader, location)
|
|
||||||
v.delete?.addToSpec(path, spec, v, serializableReader, location)
|
|
||||||
v.head?.addToSpec(path, spec, v, serializableReader, location)
|
|
||||||
v.options?.addToSpec(path, spec, v, serializableReader, location)
|
|
||||||
v.post?.addToSpec(path, spec, v, serializableReader, location)
|
|
||||||
v.put?.addToSpec(path, spec, v, serializableReader, location)
|
|
||||||
v.patch?.addToSpec(path, spec, v, serializableReader, location)
|
|
||||||
|
|
||||||
spec.paths[location] = path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(KtorExperimentalLocationsAPI::class)
|
|
||||||
private fun KClass<*>.getLocationFromClass(): String {
|
|
||||||
// todo if parent
|
|
||||||
|
|
||||||
val location = findAnnotation<Location>()
|
|
||||||
?: error("Cannot notarize a location without annotating with @Location")
|
|
||||||
|
|
||||||
val path = location.path
|
|
||||||
val parent = memberProperties.map { it.returnType.classifier as KClass<*> }.find { it.hasAnnotation<Location>() }
|
|
||||||
|
|
||||||
return if (parent == null) {
|
|
||||||
path
|
|
||||||
} else {
|
|
||||||
parent.getLocationFromClass() + path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
package io.bkbn.kompendium.locations
|
|
||||||
|
|
||||||
import Listing
|
|
||||||
import io.bkbn.kompendium.core.fixtures.TestHelpers.openApiTestAllSerializers
|
|
||||||
import io.bkbn.kompendium.core.fixtures.TestResponse
|
|
||||||
import io.bkbn.kompendium.core.metadata.GetInfo
|
|
||||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
|
||||||
import io.kotest.core.spec.style.DescribeSpec
|
|
||||||
import io.ktor.http.HttpStatusCode
|
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
|
||||||
import io.ktor.server.locations.Locations
|
|
||||||
import io.ktor.server.locations.get
|
|
||||||
import io.ktor.server.response.respondText
|
|
||||||
|
|
||||||
class KompendiumLocationsTest : DescribeSpec({
|
|
||||||
describe("Location Tests") {
|
|
||||||
it("Can notarize a simple location") {
|
|
||||||
openApiTestAllSerializers(
|
|
||||||
snapshotName = "T0001__simple_location.json",
|
|
||||||
applicationSetup = {
|
|
||||||
install(Locations)
|
|
||||||
install(NotarizedLocations()) {
|
|
||||||
locations = mapOf(
|
|
||||||
Listing::class to NotarizedLocations.LocationMetadata(
|
|
||||||
parameters = listOf(
|
|
||||||
Parameter(
|
|
||||||
name = "name",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.STRING
|
|
||||||
),
|
|
||||||
Parameter(
|
|
||||||
name = "page",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.INT
|
|
||||||
)
|
|
||||||
),
|
|
||||||
get = GetInfo.builder {
|
|
||||||
summary("Location")
|
|
||||||
description("example location")
|
|
||||||
response {
|
|
||||||
responseCode(HttpStatusCode.OK)
|
|
||||||
responseType<TestResponse>()
|
|
||||||
description("does great things")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
get<Listing> { listing ->
|
|
||||||
call.respondText("Listing ${listing.name}, page ${listing.page}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it("Can notarize nested locations") {
|
|
||||||
openApiTestAllSerializers(
|
|
||||||
snapshotName = "T0002__nested_locations.json",
|
|
||||||
applicationSetup = {
|
|
||||||
install(Locations)
|
|
||||||
install(NotarizedLocations()) {
|
|
||||||
locations = mapOf(
|
|
||||||
Type.Edit::class to NotarizedLocations.LocationMetadata(
|
|
||||||
parameters = listOf(
|
|
||||||
Parameter(
|
|
||||||
name = "name",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.STRING
|
|
||||||
)
|
|
||||||
),
|
|
||||||
get = GetInfo.builder {
|
|
||||||
summary("Edit")
|
|
||||||
description("example location")
|
|
||||||
response {
|
|
||||||
responseCode(HttpStatusCode.OK)
|
|
||||||
responseType<TestResponse>()
|
|
||||||
description("does great things")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
Type.Other::class to NotarizedLocations.LocationMetadata(
|
|
||||||
parameters = listOf(
|
|
||||||
Parameter(
|
|
||||||
name = "name",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.STRING
|
|
||||||
),
|
|
||||||
Parameter(
|
|
||||||
name = "page",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.INT
|
|
||||||
)
|
|
||||||
),
|
|
||||||
get = GetInfo.builder {
|
|
||||||
summary("Other")
|
|
||||||
description("example location")
|
|
||||||
response {
|
|
||||||
responseCode(HttpStatusCode.OK)
|
|
||||||
responseType<TestResponse>()
|
|
||||||
description("does great things")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
get<Type.Edit> { edit ->
|
|
||||||
call.respondText("Listing ${edit.parent.name}")
|
|
||||||
}
|
|
||||||
get<Type.Other> { other ->
|
|
||||||
call.respondText("Listing ${other.parent.name}, page ${other.page}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,13 +0,0 @@
|
|||||||
import io.ktor.server.locations.Location
|
|
||||||
|
|
||||||
@Location("/list/{name}/page/{page}")
|
|
||||||
data class Listing(val name: String, val page: Int)
|
|
||||||
|
|
||||||
@Location("/type/{name}")
|
|
||||||
data class Type(val name: String) {
|
|
||||||
@Location("/edit")
|
|
||||||
data class Edit(val parent: Type)
|
|
||||||
|
|
||||||
@Location("/other/{page}")
|
|
||||||
data class Other(val parent: Type, val page: Int)
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
{
|
|
||||||
"openapi": "3.1.0",
|
|
||||||
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"info": {
|
|
||||||
"title": "Test API",
|
|
||||||
"version": "1.33.7",
|
|
||||||
"description": "An amazing, fully-ish 😉 generated API spec",
|
|
||||||
"termsOfService": "https://example.com",
|
|
||||||
"contact": {
|
|
||||||
"name": "Homer Simpson",
|
|
||||||
"url": "https://gph.is/1NPUDiM",
|
|
||||||
"email": "chunkylover53@aol.com"
|
|
||||||
},
|
|
||||||
"license": {
|
|
||||||
"name": "MIT",
|
|
||||||
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"url": "https://myawesomeapi.com",
|
|
||||||
"description": "Production instance of my API"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://staging.myawesomeapi.com",
|
|
||||||
"description": "Where the fun stuff happens"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"/list/{name}/page/{page}": {
|
|
||||||
"get": {
|
|
||||||
"tags": [],
|
|
||||||
"summary": "Location",
|
|
||||||
"description": "example location",
|
|
||||||
"parameters": [],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "does great things",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/TestResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"deprecated": false
|
|
||||||
},
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"in": "path",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"required": true,
|
|
||||||
"deprecated": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "page",
|
|
||||||
"in": "path",
|
|
||||||
"schema": {
|
|
||||||
"type": "number",
|
|
||||||
"format": "int32"
|
|
||||||
},
|
|
||||||
"required": true,
|
|
||||||
"deprecated": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"webhooks": {},
|
|
||||||
"components": {
|
|
||||||
"schemas": {
|
|
||||||
"TestResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"c": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"c"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"securitySchemes": {}
|
|
||||||
},
|
|
||||||
"security": [],
|
|
||||||
"tags": []
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
{
|
|
||||||
"openapi": "3.1.0",
|
|
||||||
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"info": {
|
|
||||||
"title": "Test API",
|
|
||||||
"version": "1.33.7",
|
|
||||||
"description": "An amazing, fully-ish 😉 generated API spec",
|
|
||||||
"termsOfService": "https://example.com",
|
|
||||||
"contact": {
|
|
||||||
"name": "Homer Simpson",
|
|
||||||
"url": "https://gph.is/1NPUDiM",
|
|
||||||
"email": "chunkylover53@aol.com"
|
|
||||||
},
|
|
||||||
"license": {
|
|
||||||
"name": "MIT",
|
|
||||||
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"url": "https://myawesomeapi.com",
|
|
||||||
"description": "Production instance of my API"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://staging.myawesomeapi.com",
|
|
||||||
"description": "Where the fun stuff happens"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"/type/{name}/edit": {
|
|
||||||
"get": {
|
|
||||||
"tags": [],
|
|
||||||
"summary": "Edit",
|
|
||||||
"description": "example location",
|
|
||||||
"parameters": [],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "does great things",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/TestResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"deprecated": false
|
|
||||||
},
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"in": "path",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"required": true,
|
|
||||||
"deprecated": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"/type/{name}/other/{page}": {
|
|
||||||
"get": {
|
|
||||||
"tags": [],
|
|
||||||
"summary": "Other",
|
|
||||||
"description": "example location",
|
|
||||||
"parameters": [],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "does great things",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/TestResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"deprecated": false
|
|
||||||
},
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"in": "path",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"required": true,
|
|
||||||
"deprecated": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "page",
|
|
||||||
"in": "path",
|
|
||||||
"schema": {
|
|
||||||
"type": "number",
|
|
||||||
"format": "int32"
|
|
||||||
},
|
|
||||||
"required": true,
|
|
||||||
"deprecated": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"webhooks": {},
|
|
||||||
"components": {
|
|
||||||
"schemas": {
|
|
||||||
"TestResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"c": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"c"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"securitySchemes": {}
|
|
||||||
},
|
|
||||||
"security": [],
|
|
||||||
"tags": []
|
|
||||||
}
|
|
@ -19,10 +19,11 @@ sourdoughLibrary {
|
|||||||
dependencies {
|
dependencies {
|
||||||
// Versions
|
// Versions
|
||||||
val detektVersion: String by project
|
val detektVersion: String by project
|
||||||
|
val kotlinSerializeVersion: String by project
|
||||||
|
|
||||||
api(projects.kompendiumJsonSchema)
|
api(projects.kompendiumJsonSchema)
|
||||||
api(projects.kompendiumEnrichment)
|
api(projects.kompendiumEnrichment)
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializeVersion")
|
||||||
|
|
||||||
// Formatting
|
// Formatting
|
||||||
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
||||||
|
@ -13,11 +13,11 @@ sourdoughApp {
|
|||||||
dependencies {
|
dependencies {
|
||||||
// IMPLEMENTATION
|
// IMPLEMENTATION
|
||||||
implementation(projects.kompendiumCore)
|
implementation(projects.kompendiumCore)
|
||||||
implementation(projects.kompendiumLocations)
|
|
||||||
implementation(projects.kompendiumResources)
|
implementation(projects.kompendiumResources)
|
||||||
implementation(projects.kompendiumProtobufJavaConverter)
|
implementation(projects.kompendiumProtobufJavaConverter)
|
||||||
|
|
||||||
// Ktor
|
// Ktor
|
||||||
|
val kotlinSerializeVersion: String by project
|
||||||
val ktorVersion: String by project
|
val ktorVersion: String by project
|
||||||
|
|
||||||
implementation("io.ktor:ktor-server-core:$ktorVersion")
|
implementation("io.ktor:ktor-server-core:$ktorVersion")
|
||||||
@ -30,7 +30,6 @@ dependencies {
|
|||||||
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
|
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-serialization-jackson:$ktorVersion")
|
implementation("io.ktor:ktor-serialization-jackson:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-serialization-gson:$ktorVersion")
|
implementation("io.ktor:ktor-serialization-gson:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-server-locations:$ktorVersion")
|
|
||||||
implementation("io.ktor:ktor-server-resources:$ktorVersion")
|
implementation("io.ktor:ktor-server-resources:$ktorVersion")
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
@ -41,9 +40,9 @@ dependencies {
|
|||||||
implementation("org.slf4j:slf4j-simple:2.0.16")
|
implementation("org.slf4j:slf4j-simple:2.0.16")
|
||||||
|
|
||||||
// YAML
|
// YAML
|
||||||
implementation("com.charleskorn.kaml:kaml:0.59.0")
|
implementation("com.charleskorn.kaml:kaml:0.61.0")
|
||||||
|
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializeVersion")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
|
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
|
||||||
|
|
||||||
implementation("joda-time:joda-time:2.13.0")
|
implementation("joda-time:joda-time:2.13.0")
|
||||||
|
@ -15,7 +15,6 @@ import io.bkbn.kompendium.playground.util.Util.baseSpec
|
|||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import io.ktor.server.application.Application
|
import io.ktor.server.application.Application
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.application.install
|
||||||
import io.ktor.server.auth.Authentication
|
import io.ktor.server.auth.Authentication
|
||||||
import io.ktor.server.auth.UserIdPrincipal
|
import io.ktor.server.auth.UserIdPrincipal
|
||||||
|
@ -15,7 +15,6 @@ import io.bkbn.kompendium.playground.util.Util.baseSpec
|
|||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import io.ktor.server.application.Application
|
import io.ktor.server.application.Application
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.application.install
|
||||||
import io.ktor.server.auth.Authentication
|
import io.ktor.server.auth.Authentication
|
||||||
import io.ktor.server.auth.UserIdPrincipal
|
import io.ktor.server.auth.UserIdPrincipal
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
package io.bkbn.kompendium.playground
|
|
||||||
|
|
||||||
import io.bkbn.kompendium.core.metadata.GetInfo
|
|
||||||
import io.bkbn.kompendium.core.plugin.NotarizedApplication
|
|
||||||
import io.bkbn.kompendium.core.routes.redoc
|
|
||||||
import io.bkbn.kompendium.core.routes.swagger
|
|
||||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
|
||||||
import io.bkbn.kompendium.locations.NotarizedLocations
|
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
|
||||||
import io.bkbn.kompendium.oas.serialization.KompendiumSerializersModule
|
|
||||||
import io.bkbn.kompendium.playground.util.ExampleResponse
|
|
||||||
import io.bkbn.kompendium.playground.util.Listing
|
|
||||||
import io.bkbn.kompendium.playground.util.Util.baseSpec
|
|
||||||
import io.ktor.http.HttpStatusCode
|
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
|
||||||
import io.ktor.server.application.Application
|
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
|
||||||
import io.ktor.server.cio.CIO
|
|
||||||
import io.ktor.server.engine.embeddedServer
|
|
||||||
import io.ktor.server.locations.Locations
|
|
||||||
import io.ktor.server.locations.get
|
|
||||||
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
|
|
||||||
import io.ktor.server.response.respondText
|
|
||||||
import io.ktor.server.routing.routing
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
embeddedServer(
|
|
||||||
CIO,
|
|
||||||
port = 8081,
|
|
||||||
module = Application::mainModule
|
|
||||||
).start(wait = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Application.mainModule() {
|
|
||||||
install(Locations)
|
|
||||||
install(ContentNegotiation) {
|
|
||||||
json(Json {
|
|
||||||
serializersModule = KompendiumSerializersModule.module
|
|
||||||
encodeDefaults = true
|
|
||||||
explicitNulls = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
install(NotarizedApplication()) {
|
|
||||||
spec = { baseSpec }
|
|
||||||
}
|
|
||||||
install(NotarizedLocations()) {
|
|
||||||
locations = mapOf(
|
|
||||||
Listing::class to NotarizedLocations.LocationMetadata(
|
|
||||||
parameters = listOf(
|
|
||||||
Parameter(
|
|
||||||
name = "name",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.STRING
|
|
||||||
),
|
|
||||||
Parameter(
|
|
||||||
name = "page",
|
|
||||||
`in` = Parameter.Location.path,
|
|
||||||
schema = TypeDefinition.INT
|
|
||||||
)
|
|
||||||
),
|
|
||||||
get = GetInfo.builder {
|
|
||||||
summary("Get user by id")
|
|
||||||
description("A very neat endpoint!")
|
|
||||||
response {
|
|
||||||
responseCode(HttpStatusCode.OK)
|
|
||||||
responseType<ExampleResponse>()
|
|
||||||
description("Will return whether or not the user is real 😱")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
routing {
|
|
||||||
swagger(pageTitle = "Simple API Docs")
|
|
||||||
redoc(pageTitle = "Simple API Docs")
|
|
||||||
get<Listing> { listing ->
|
|
||||||
call.respondText("Listing ${listing.name}, page ${listing.page}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,5 @@
|
|||||||
package io.bkbn.kompendium.playground.util
|
package io.bkbn.kompendium.playground.util
|
||||||
|
|
||||||
import io.ktor.server.locations.KtorExperimentalLocationsAPI
|
|
||||||
import io.ktor.server.locations.Location
|
|
||||||
import kotlinx.datetime.Instant
|
import kotlinx.datetime.Instant
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@ -29,12 +27,3 @@ data class CustomTypeResponse(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ExceptionResponse(val message: String)
|
data class ExceptionResponse(val message: String)
|
||||||
|
|
||||||
@Location("/list/{name}/page/{page}")
|
|
||||||
data class Listing(val name: String, val page: Int)
|
|
||||||
|
|
||||||
@Location("/type/{name}") data class Type(val name: String) {
|
|
||||||
// In these classes we have to include the `name` property matching the parent.
|
|
||||||
@Location("/edit") data class Edit(val parent: Type)
|
|
||||||
@Location("/other/{page}") data class Other(val parent: Type, val page: Int)
|
|
||||||
}
|
|
||||||
|
@ -19,12 +19,13 @@ sourdoughLibrary {
|
|||||||
dependencies {
|
dependencies {
|
||||||
// Versions
|
// Versions
|
||||||
val detektVersion: String by project
|
val detektVersion: String by project
|
||||||
|
val kotlinVersion: String by project
|
||||||
|
val kotlinSerializeVersion: String by project
|
||||||
|
|
||||||
implementation(projects.kompendiumJsonSchema)
|
implementation(projects.kompendiumJsonSchema)
|
||||||
implementation("com.google.protobuf:protobuf-java:3.25.5")
|
implementation("com.google.protobuf:protobuf-java:3.25.5")
|
||||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.25")
|
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializeVersion")
|
||||||
|
|
||||||
// Formatting
|
// Formatting
|
||||||
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
||||||
|
@ -18,12 +18,13 @@ sourdoughLibrary {
|
|||||||
dependencies {
|
dependencies {
|
||||||
// Versions
|
// Versions
|
||||||
val detektVersion: String by project
|
val detektVersion: String by project
|
||||||
|
val ktorVersion: String by project
|
||||||
|
|
||||||
// IMPLEMENTATION
|
// IMPLEMENTATION
|
||||||
|
|
||||||
implementation(projects.kompendiumCore)
|
implementation(projects.kompendiumCore)
|
||||||
implementation("io.ktor:ktor-server-core:2.3.12")
|
implementation("io.ktor:ktor-server-core:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-server-resources:2.3.12")
|
implementation("io.ktor:ktor-server-resources:$ktorVersion")
|
||||||
|
|
||||||
// TESTING
|
// TESTING
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
|||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.kotest.core.spec.style.DescribeSpec
|
import io.kotest.core.spec.style.DescribeSpec
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.application.install
|
||||||
import io.ktor.server.resources.Resources
|
import io.ktor.server.resources.Resources
|
||||||
import io.ktor.server.resources.get
|
import io.ktor.server.resources.get
|
||||||
|
@ -4,7 +4,6 @@ include("core")
|
|||||||
include("enrichment")
|
include("enrichment")
|
||||||
include("oas")
|
include("oas")
|
||||||
include("playground")
|
include("playground")
|
||||||
include("locations")
|
|
||||||
include("json-schema")
|
include("json-schema")
|
||||||
include("protobuf-java-converter")
|
include("protobuf-java-converter")
|
||||||
include("resources")
|
include("resources")
|
||||||
|
Reference in New Issue
Block a user