Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
bf6d08c2bd | |||
68bae4918e | |||
592c116c3b | |||
c7fe5c288f | |||
e059633055 | |||
884a50fc83 | |||
588e52c9df | |||
f49fcb2a22 | |||
0a9475a7ab | |||
f8fbb7ad25 | |||
f792fb5d1f | |||
845d1a971d | |||
9396b2ecfe | |||
d74b7b3f28 | |||
e783630845 |
14
CHANGELOG.md
14
CHANGELOG.md
@ -6,14 +6,24 @@
|
||||
|
||||
### Changed
|
||||
|
||||
- Route generation with parameters doesn`t add parameters to the path.
|
||||
|
||||
### Remove
|
||||
|
||||
---
|
||||
|
||||
## Released
|
||||
|
||||
## [3.14.4] - June 5th, 2023
|
||||
|
||||
### Changed
|
||||
|
||||
- Components definitions were not in the proper schema section. Prefixed the path with component slug in `protobuf java converter`.
|
||||
|
||||
## [3.14.3] - May 22nd, 2023
|
||||
|
||||
### Added
|
||||
|
||||
- Added `required` parameter in request info builder.
|
||||
|
||||
## [3.14.2] - May 8rd, 2023
|
||||
|
||||
### Changed
|
||||
|
@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
kotlin("jvm") version "1.8.20" apply false
|
||||
kotlin("plugin.serialization") version "1.8.20" apply false
|
||||
kotlin("jvm") version "1.8.21" apply false
|
||||
kotlin("plugin.serialization") version "1.8.21" apply false
|
||||
id("io.bkbn.sourdough.library.jvm") version "0.12.0" apply false
|
||||
id("io.bkbn.sourdough.application.jvm") version "0.12.0" apply false
|
||||
id("io.bkbn.sourdough.root") version "0.12.0"
|
||||
|
@ -59,7 +59,7 @@ dependencies {
|
||||
|
||||
testFixturesApi("dev.forst:ktor-api-key:2.2.4")
|
||||
|
||||
testFixturesApi("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
testFixturesApi("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
}
|
||||
|
||||
testing {
|
||||
|
@ -10,7 +10,8 @@ class RequestInfo private constructor(
|
||||
val typeEnrichment: TypeEnrichment<*>?,
|
||||
val description: String,
|
||||
val examples: Map<String, MediaType.Example>?,
|
||||
val mediaTypes: Set<String>
|
||||
val mediaTypes: Set<String>,
|
||||
val required: Boolean
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@ -27,6 +28,11 @@ class RequestInfo private constructor(
|
||||
private var description: String? = null
|
||||
private var examples: Map<String, MediaType.Example>? = null
|
||||
private var mediaTypes: Set<String>? = null
|
||||
private var required: Boolean? = null
|
||||
|
||||
fun required(r: Boolean) = apply {
|
||||
this.required = r
|
||||
}
|
||||
|
||||
fun requestType(t: KType) = apply {
|
||||
this.requestType = t
|
||||
@ -56,7 +62,8 @@ class RequestInfo private constructor(
|
||||
description = description ?: error("Description must be present"),
|
||||
typeEnrichment = typeEnrichment,
|
||||
examples = examples,
|
||||
mediaTypes = mediaTypes ?: setOf("application/json")
|
||||
mediaTypes = mediaTypes ?: setOf("application/json"),
|
||||
required = required ?: true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ object Helpers {
|
||||
mediaTypes = reqInfo.mediaTypes,
|
||||
enrichment = reqInfo.typeEnrichment
|
||||
),
|
||||
required = true
|
||||
required = reqInfo.required
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@ import io.bkbn.kompendium.core.util.polymorphicResponse
|
||||
import io.bkbn.kompendium.core.util.postNoReqBody
|
||||
import io.bkbn.kompendium.core.util.primitives
|
||||
import io.bkbn.kompendium.core.util.reqRespExamples
|
||||
import io.bkbn.kompendium.core.util.optionalReqExample
|
||||
import io.bkbn.kompendium.core.util.requiredParams
|
||||
import io.bkbn.kompendium.core.util.responseHeaders
|
||||
import io.bkbn.kompendium.core.util.returnsList
|
||||
@ -178,6 +179,9 @@ class KompendiumTest : DescribeSpec({
|
||||
it("Can describe example parameters") {
|
||||
openApiTestAllSerializers("T0021__example_parameters.json") { exampleParams() }
|
||||
}
|
||||
it("Can generate example optional request body") {
|
||||
openApiTestAllSerializers("T0069__example_optional_req.json") { optionalReqExample() }
|
||||
}
|
||||
}
|
||||
describe("Defaults") {
|
||||
it("Can generate a default parameter value") {
|
||||
|
@ -55,3 +55,30 @@ fun Routing.exampleParams() = basicGetGenerator<TestResponse>(
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
fun Routing.optionalReqExample() {
|
||||
route(rootPath) {
|
||||
install(NotarizedRoute()) {
|
||||
post = PostInfo.builder {
|
||||
summary(defaultPathSummary)
|
||||
description(defaultPathDescription)
|
||||
request {
|
||||
description(defaultRequestDescription)
|
||||
requestType<TestRequest>()
|
||||
examples(
|
||||
"Testerina" to TestRequest(TestNested("asdf"), 1.5, emptyList())
|
||||
)
|
||||
required(false)
|
||||
}
|
||||
response {
|
||||
description(defaultResponseDescription)
|
||||
responseCode(HttpStatusCode.OK)
|
||||
responseType<TestResponse>()
|
||||
examples(
|
||||
"Testerino" to TestResponse("Heya")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
136
core/src/test/resources/T0069__example_optional_req.json
Normal file
136
core/src/test/resources/T0069__example_optional_req.json
Normal file
@ -0,0 +1,136 @@
|
||||
{
|
||||
"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": {
|
||||
"/": {
|
||||
"post": {
|
||||
"tags": [],
|
||||
"summary": "Great Summary!",
|
||||
"description": "testing more",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"description": "You gotta send it",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TestRequest"
|
||||
},
|
||||
"examples": {
|
||||
"Testerina": {
|
||||
"value": {
|
||||
"fieldName": {
|
||||
"nesty": "asdf"
|
||||
},
|
||||
"b": 1.5,
|
||||
"aaa": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A Successful Endeavor",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TestResponse"
|
||||
},
|
||||
"examples": {
|
||||
"Testerino": {
|
||||
"value": {
|
||||
"c": "Heya"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated": false
|
||||
},
|
||||
"parameters": []
|
||||
}
|
||||
},
|
||||
"webhooks": {},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"TestResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"c"
|
||||
]
|
||||
},
|
||||
"TestRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aaa": {
|
||||
"items": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"b": {
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
},
|
||||
"fieldName": {
|
||||
"$ref": "#/components/schemas/TestNested"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"aaa",
|
||||
"b",
|
||||
"fieldName"
|
||||
]
|
||||
},
|
||||
"TestNested": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nesty": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"nesty"
|
||||
]
|
||||
}
|
||||
},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
# Kompendium
|
||||
project.version=3.14.2
|
||||
project.version=3.14.4
|
||||
# Kotlin
|
||||
kotlin.code.style=official
|
||||
# Gradle
|
||||
@ -9,6 +9,6 @@ org.gradle.jvmargs=-Xmx2000m
|
||||
org.gradle.parallel=true
|
||||
|
||||
# Dependencies
|
||||
ktorVersion=2.3.0
|
||||
kotestVersion=5.6.1
|
||||
ktorVersion=2.3.1
|
||||
kotestVersion=5.6.2
|
||||
detektVersion=1.22.0
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
7
gradlew
vendored
7
gradlew
vendored
@ -85,9 +85,6 @@ done
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
|
@ -23,8 +23,8 @@ dependencies {
|
||||
// Kompendium
|
||||
api(projects.kompendiumEnrichment)
|
||||
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.20")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.21")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
|
||||
// Formatting
|
||||
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
||||
|
@ -8,7 +8,7 @@ import kotlin.reflect.KType
|
||||
|
||||
object Helpers {
|
||||
|
||||
private const val COMPONENT_SLUG = "#/components/schemas"
|
||||
const val COMPONENT_SLUG = "#/components/schemas"
|
||||
|
||||
fun KType.getSlug(enrichment: Enrichment? = null) = when (enrichment) {
|
||||
is TypeEnrichment<*> -> getEnrichedSlug(enrichment)
|
||||
|
@ -22,8 +22,8 @@ dependencies {
|
||||
// IMPLEMENTATION
|
||||
|
||||
implementation(projects.kompendiumCore)
|
||||
implementation("io.ktor:ktor-server-core:2.3.0")
|
||||
implementation("io.ktor:ktor-server-locations:2.3.0")
|
||||
implementation("io.ktor:ktor-server-core:2.3.1")
|
||||
implementation("io.ktor:ktor-server-locations:2.3.1")
|
||||
|
||||
// TESTING
|
||||
|
||||
|
@ -22,7 +22,7 @@ dependencies {
|
||||
|
||||
api(projects.kompendiumJsonSchema)
|
||||
api(projects.kompendiumEnrichment)
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
|
||||
// Formatting
|
||||
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
||||
|
@ -41,7 +41,7 @@ dependencies {
|
||||
implementation("org.slf4j:slf4j-simple:2.0.7")
|
||||
|
||||
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
||||
|
||||
implementation("joda-time:joda-time:2.12.5")
|
||||
|
@ -22,9 +22,9 @@ dependencies {
|
||||
|
||||
|
||||
implementation(projects.kompendiumJsonSchema)
|
||||
implementation("com.google.protobuf:protobuf-java:3.22.3")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.20")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
implementation("com.google.protobuf:protobuf-java:3.23.2")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.21")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
|
||||
// Formatting
|
||||
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
|
||||
|
@ -9,6 +9,7 @@ import io.bkbn.kompendium.json.schema.definition.MapDefinition
|
||||
import io.bkbn.kompendium.json.schema.definition.NullableDefinition
|
||||
import io.bkbn.kompendium.json.schema.definition.ReferenceDefinition
|
||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
||||
import io.bkbn.kompendium.json.schema.util.Helpers
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.full.createType
|
||||
|
||||
@ -150,7 +151,7 @@ fun fromTypeToSchema(
|
||||
type = "string",
|
||||
enum = javaProtoField.enumType.values.map { it.name }.toSet()
|
||||
)
|
||||
ReferenceDefinition(javaProtoField.enumType.name)
|
||||
ReferenceDefinition("${Helpers.COMPONENT_SLUG}/${javaProtoField.enumType.name}")
|
||||
}
|
||||
Descriptors.FieldDescriptor.JavaType.MESSAGE -> {
|
||||
// Traverse through possible nested messages
|
||||
@ -160,7 +161,7 @@ fun fromTypeToSchema(
|
||||
it.jsonName to fromNestedTypeToSchema(it, cache)
|
||||
}.toMap()
|
||||
)
|
||||
ReferenceDefinition(javaProtoField.messageType.name)
|
||||
ReferenceDefinition("${Helpers.COMPONENT_SLUG}/${javaProtoField.messageType.name}")
|
||||
}
|
||||
null -> NullableDefinition()
|
||||
}
|
||||
|
@ -2,17 +2,21 @@ package io.bkbn.kompendium.protobufjavaconverter.converters
|
||||
|
||||
import com.google.protobuf.Descriptors
|
||||
import com.google.protobuf.GeneratedMessageV3
|
||||
import io.bkbn.kompendium.core.fixtures.TestHelpers.openApiTestAllSerializers
|
||||
import io.bkbn.kompendium.core.metadata.PostInfo
|
||||
import io.bkbn.kompendium.core.plugin.NotarizedRoute
|
||||
import io.bkbn.kompendium.json.schema.definition.ArrayDefinition
|
||||
import io.bkbn.kompendium.json.schema.definition.EnumDefinition
|
||||
import io.bkbn.kompendium.json.schema.definition.JsonSchema
|
||||
import io.bkbn.kompendium.json.schema.definition.MapDefinition
|
||||
import io.bkbn.kompendium.json.schema.definition.ReferenceDefinition
|
||||
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
|
||||
import io.bkbn.kompendium.json.schema.util.Helpers
|
||||
import io.bkbn.kompendium.protobufjavaconverter.Corpus
|
||||
import io.bkbn.kompendium.protobufjavaconverter.DoubleNestedMessage
|
||||
import io.bkbn.kompendium.protobufjavaconverter.NestedMapMessage
|
||||
import io.bkbn.kompendium.protobufjavaconverter.EnumMessage
|
||||
import io.bkbn.kompendium.protobufjavaconverter.GoogleTypes
|
||||
import io.bkbn.kompendium.protobufjavaconverter.NestedMapMessage
|
||||
import io.bkbn.kompendium.protobufjavaconverter.NestedMessage
|
||||
import io.bkbn.kompendium.protobufjavaconverter.RepeatedEnumMessage
|
||||
import io.bkbn.kompendium.protobufjavaconverter.RepeatedMessage
|
||||
@ -23,10 +27,15 @@ import io.kotest.matchers.maps.shouldContainExactly
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.types.shouldBeTypeOf
|
||||
import io.kotest.matchers.types.shouldNotBeTypeOf
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.server.application.install
|
||||
import io.ktor.server.routing.Route
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.full.createType
|
||||
|
||||
class FieldDescriptiorConvertersKtTest : DescribeSpec({
|
||||
|
||||
val componentSlug = Helpers.COMPONENT_SLUG
|
||||
describe("fromTypeToSchemaTests") {
|
||||
val simpleMessageDescriptor = SimpleTestMessage.getDescriptor()
|
||||
it("java int field should return TypeDefinition INT") {
|
||||
@ -77,7 +86,7 @@ class FieldDescriptiorConvertersKtTest : DescribeSpec({
|
||||
val message = NestedMessage.getDescriptor()
|
||||
val result = fromNestedTypeToSchema(message.findFieldByName("nested_field"))
|
||||
result.shouldBeTypeOf<ReferenceDefinition>()
|
||||
result.`$ref`.shouldBe(message.findFieldByName("nested_field").messageType.name)
|
||||
result.`$ref`.shouldBe("${Helpers.COMPONENT_SLUG}/${message.findFieldByName("nested_field").messageType.name}")
|
||||
}
|
||||
|
||||
it("Repeated message should return ArrayDefinition") {
|
||||
@ -85,7 +94,7 @@ class FieldDescriptiorConvertersKtTest : DescribeSpec({
|
||||
val result = fromNestedTypeToSchema(message.findFieldByName("repeated_field"))
|
||||
result.shouldBeTypeOf<ArrayDefinition>()
|
||||
result.items.shouldBeTypeOf<ReferenceDefinition>()
|
||||
(result.items as ReferenceDefinition).`$ref`.shouldBe(SimpleTestMessage.getDescriptor().name)
|
||||
(result.items as ReferenceDefinition).`$ref`.shouldBe("$componentSlug/${SimpleTestMessage.getDescriptor().name}")
|
||||
}
|
||||
|
||||
it("Repeated enum message should return ArrayDefinition") {
|
||||
@ -93,7 +102,7 @@ class FieldDescriptiorConvertersKtTest : DescribeSpec({
|
||||
val result: JsonSchema = fromNestedTypeToSchema(message.findFieldByName("repeated_field"))
|
||||
result.shouldBeTypeOf<ArrayDefinition>()
|
||||
result.items.shouldBeTypeOf<ReferenceDefinition>()
|
||||
(result.items as ReferenceDefinition).`$ref`.shouldBe(Corpus.getDescriptor().name)
|
||||
(result.items as ReferenceDefinition).`$ref`.shouldBe("$componentSlug/${Corpus.getDescriptor().name}")
|
||||
}
|
||||
|
||||
it("SimpleMapMessage message should return MapDefinition") {
|
||||
@ -169,7 +178,7 @@ class FieldDescriptiorConvertersKtTest : DescribeSpec({
|
||||
// Our nested field should be a reference
|
||||
result.shouldBeTypeOf<ReferenceDefinition>()
|
||||
// Our nested field should be a reference to simplemessage
|
||||
result.`$ref`.shouldBe(SimpleTestMessage.getDescriptor().name)
|
||||
result.`$ref`.shouldBe("$componentSlug/${SimpleTestMessage.getDescriptor().name}")
|
||||
}
|
||||
|
||||
it("Double nested message to schema") {
|
||||
@ -201,11 +210,11 @@ class FieldDescriptiorConvertersKtTest : DescribeSpec({
|
||||
// Our nested field should be a reference
|
||||
result.shouldBeTypeOf<ReferenceDefinition>()
|
||||
// it should be a reference to our nested message
|
||||
result.`$ref`.shouldBe(NestedMessage.getDescriptor().name)
|
||||
result.`$ref`.shouldBe("$componentSlug/${NestedMessage.getDescriptor().name}")
|
||||
val nestedResult = (resultSchema[NestedMessage::class.createType()] as TypeDefinition).properties!!["nestedField"]
|
||||
nestedResult.shouldBeTypeOf<ReferenceDefinition>()
|
||||
// Our nested message reference should be pointing to simpleTest message
|
||||
nestedResult.`$ref`.shouldBe(SimpleTestMessage.getDescriptor().name)
|
||||
nestedResult.`$ref`.shouldBe("$componentSlug/${SimpleTestMessage.getDescriptor().name}")
|
||||
// last but not least we should have definition for our SimpleTest message which is not a reference
|
||||
(resultSchema[SimpleTestMessage::class.createType()] as TypeDefinition).shouldNotBeTypeOf<ReferenceDefinition>()
|
||||
}
|
||||
@ -235,6 +244,39 @@ class FieldDescriptiorConvertersKtTest : DescribeSpec({
|
||||
testMessageBasics(message)
|
||||
}
|
||||
}
|
||||
|
||||
describe("Test spec generation") {
|
||||
it("Generates simple message references") {
|
||||
openApiTestAllSerializers(
|
||||
"T0001__simpletestmessage_post.json",
|
||||
testMessageBasics(SimpleTestMessage.getDefaultInstance())
|
||||
) { testRoute<SimpleTestMessage>() }
|
||||
}
|
||||
it("Generates enum references") {
|
||||
openApiTestAllSerializers(
|
||||
"T0002__enummessage_post.json",
|
||||
testMessageBasics(EnumMessage.getDefaultInstance())
|
||||
) { testRoute<EnumMessage>() }
|
||||
}
|
||||
it("Generates repeated type references") {
|
||||
openApiTestAllSerializers(
|
||||
"T0003__repeatedmessage_post.json",
|
||||
testMessageBasics(RepeatedMessage.getDefaultInstance())
|
||||
) { testRoute<RepeatedMessage>() }
|
||||
}
|
||||
it("Generates nested type references") {
|
||||
openApiTestAllSerializers(
|
||||
"T0004__nestedmessage_post.json",
|
||||
testMessageBasics(NestedMessage.getDefaultInstance())
|
||||
) { testRoute<NestedMessage>() }
|
||||
}
|
||||
it("Generates nested map type references") {
|
||||
openApiTestAllSerializers(
|
||||
"T0005__nestedmapmessage_post.json",
|
||||
testMessageBasics(NestedMapMessage.getDefaultInstance())
|
||||
) { testRoute<NestedMapMessage>() }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
@ -256,3 +298,25 @@ fun testMessageBasics(message: GeneratedMessageV3): Map<KType, JsonSchema> {
|
||||
}
|
||||
return resultSchema
|
||||
}
|
||||
|
||||
private const val DEFAULT_RESPONSE_DESCRIPTION = "A Successful Endeavor"
|
||||
private const val DEFAULT_REQUEST_DESCRIPTION = "You gotta send it"
|
||||
private const val DEFAULT_PATH_SUMMARY = "Great Summary!"
|
||||
private const val DEFAULT_PATH_DESCRIPTION = "testing more"
|
||||
private inline fun <reified T> Route.testRoute() {
|
||||
install(NotarizedRoute()) {
|
||||
post = PostInfo.builder {
|
||||
summary(DEFAULT_PATH_SUMMARY)
|
||||
description(DEFAULT_PATH_DESCRIPTION)
|
||||
request {
|
||||
requestType<Unit>()
|
||||
description(DEFAULT_REQUEST_DESCRIPTION)
|
||||
}
|
||||
response {
|
||||
responseCode(HttpStatusCode.OK)
|
||||
responseType<T>()
|
||||
description(DEFAULT_RESPONSE_DESCRIPTION)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,127 @@
|
||||
{
|
||||
"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": {
|
||||
"/": {
|
||||
"post": {
|
||||
"tags": [],
|
||||
"summary": "Great Summary!",
|
||||
"description": "testing more",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"description": "You gotta send it",
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A Successful Endeavor",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SimpleTestMessage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated": false
|
||||
},
|
||||
"parameters": []
|
||||
}
|
||||
},
|
||||
"webhooks": {},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"SimpleTestMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"myTestDouble": {
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
},
|
||||
"myTestFloat": {
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
},
|
||||
"myTestInt32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestInt64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestUint32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestUint64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestSint32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestSint64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestFixed32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestFixed64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestSfixed32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestSfixed64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestBool": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"myTestBytes": {
|
||||
"type": "string"
|
||||
},
|
||||
"myTestString": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
{
|
||||
"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": {
|
||||
"/": {
|
||||
"post": {
|
||||
"tags": [],
|
||||
"summary": "Great Summary!",
|
||||
"description": "testing more",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"description": "You gotta send it",
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A Successful Endeavor",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/EnumMessage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated": false
|
||||
},
|
||||
"parameters": []
|
||||
}
|
||||
},
|
||||
"webhooks": {},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"EnumMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"corpus": {
|
||||
"$ref": "#/components/schemas/Corpus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Corpus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"CORPUS_UNSPECIFIED",
|
||||
"CORPUS_UNIVERSAL",
|
||||
"CORPUS_WEB",
|
||||
"CORPUS_IMAGES",
|
||||
"CORPUS_LOCAL",
|
||||
"CORPUS_NEWS",
|
||||
"CORPUS_PRODUCTS",
|
||||
"CORPUS_VIDEO"
|
||||
]
|
||||
}
|
||||
},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
{
|
||||
"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": {
|
||||
"/": {
|
||||
"post": {
|
||||
"tags": [],
|
||||
"summary": "Great Summary!",
|
||||
"description": "testing more",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"description": "You gotta send it",
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A Successful Endeavor",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/RepeatedMessage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated": false
|
||||
},
|
||||
"parameters": []
|
||||
}
|
||||
},
|
||||
"webhooks": {},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"RepeatedMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"repeatedField": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SimpleTestMessage"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SimpleTestMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"myTestDouble": {
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
},
|
||||
"myTestFloat": {
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
},
|
||||
"myTestInt32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestInt64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestUint32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestUint64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestSint32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestSint64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestFixed32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestFixed64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestSfixed32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestSfixed64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestBool": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"myTestBytes": {
|
||||
"type": "string"
|
||||
},
|
||||
"myTestString": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
{
|
||||
"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": {
|
||||
"/": {
|
||||
"post": {
|
||||
"tags": [],
|
||||
"summary": "Great Summary!",
|
||||
"description": "testing more",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"description": "You gotta send it",
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A Successful Endeavor",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NestedMessage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated": false
|
||||
},
|
||||
"parameters": []
|
||||
}
|
||||
},
|
||||
"webhooks": {},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"NestedMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nestedField": {
|
||||
"$ref": "#/components/schemas/SimpleTestMessage"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SimpleTestMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"myTestDouble": {
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
},
|
||||
"myTestFloat": {
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
},
|
||||
"myTestInt32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestInt64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestUint32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestUint64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestSint32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestSint64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestFixed32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestFixed64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestSfixed32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestSfixed64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestBool": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"myTestBytes": {
|
||||
"type": "string"
|
||||
},
|
||||
"myTestString": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
{
|
||||
"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": {
|
||||
"/": {
|
||||
"post": {
|
||||
"tags": [],
|
||||
"summary": "Great Summary!",
|
||||
"description": "testing more",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"description": "You gotta send it",
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A Successful Endeavor",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NestedMapMessage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated": false
|
||||
},
|
||||
"parameters": []
|
||||
}
|
||||
},
|
||||
"webhooks": {},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"NestedMapMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mapField": {
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"myVariable0": {
|
||||
"$ref": "#/components/schemas/SimpleTestMessage"
|
||||
},
|
||||
"myVariable1": {
|
||||
"$ref": "#/components/schemas/SimpleTestMessage"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SimpleTestMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"myTestDouble": {
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
},
|
||||
"myTestFloat": {
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
},
|
||||
"myTestInt32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestInt64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestUint32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestUint64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestSint32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestSint64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestFixed32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestFixed64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestSfixed32": {
|
||||
"type": "number",
|
||||
"format": "int32"
|
||||
},
|
||||
"myTestSfixed64": {
|
||||
"type": "number",
|
||||
"format": "int64"
|
||||
},
|
||||
"myTestBool": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"myTestBytes": {
|
||||
"type": "string"
|
||||
},
|
||||
"myTestString": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
@ -22,8 +22,8 @@ dependencies {
|
||||
// IMPLEMENTATION
|
||||
|
||||
implementation(projects.kompendiumCore)
|
||||
implementation("io.ktor:ktor-server-core:2.3.0")
|
||||
implementation("io.ktor:ktor-server-resources:2.3.0")
|
||||
implementation("io.ktor:ktor-server-core:2.3.1")
|
||||
implementation("io.ktor:ktor-server-resources:2.3.1")
|
||||
|
||||
// TESTING
|
||||
|
||||
|
Reference in New Issue
Block a user