Compare commits

..

18 Commits

91 changed files with 1576 additions and 625 deletions

View File

@ -2,6 +2,9 @@ name: Publish to GitHub Packages
on: on:
push: push:
branches: [ main ] branches: [ main ]
env:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SONATYPE_SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SONATYPE_SIGNING_PASSWORD }}
jobs: jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -18,6 +21,6 @@ jobs:
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }} key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle restore-keys: ${{ runner.os }}-gradle
- name: Publish package - name: Publish package
run: ./gradlew publish run: ./gradlew publishAllPublicationsToGithubPackagesRepository
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -4,8 +4,11 @@ on:
types: types:
- prereleased - prereleased
- released - released
env:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SONATYPE_SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SONATYPE_SIGNING_PASSWORD }}
jobs: jobs:
publish: publish-to-github:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -19,7 +22,26 @@ jobs:
path: ~/.gradle/caches path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }} key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle restore-keys: ${{ runner.os }}-gradle
- name: Publish package - name: Publish packages to Github
run: ./gradlew publish -Prelease=true run: ./gradlew publishAllPublicationsToGithubPackagesRepository -Prelease=true
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-to-nexus:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '11'
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle
- name: Publish packages to Github
run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -Prelease=true
env:
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USER }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}

View File

@ -1,5 +1,64 @@
# Changelog # Changelog
## [1.5.0] - July 25th, 2021
### Changed
- Added support for BigInteger and BigDecimal in response types
## [1.4.0] - July 22nd, 2021
### Changed
- Decreased jvmTarget version from 11 to 1.8
## [1.3.0] - June 4th, 2021
### Changed
- Explicitly encode JSON object by default
## [1.2.3] - June 3rd, 2021
### Added
- Updates showing/explaining serializer agnostic approach
## [1.2.2] - May 23rd, 2021
This is just to get my repo back to normal now that I have confirmed sonatype publish is happening
## [1.2.0] - May 23rd, 2021
### Added
- Finally, successfully pushed to Maven Central!!!
## [1.1.0] - May 19th, 2021
### Added
- Support for sealed classes 🔥
- Support for generic classes ☄️
## [1.0.1] - May 10th, 2021
### Changed
- a word to sweep my rude commit message to Nexus under the rug
## [1.0.0] - May 9th, 2021
### Added
- SonaType integration to publish to MavenCentral
### [1.0.0-rc] - May 8th, 2021
### Changed
- Migrated to io.bkbn group and package name
### [1.0.0-beta] - May 6th, 2021 ### [1.0.0-beta] - May 6th, 2021
### Added ### Added

View File

@ -1,5 +1,7 @@
# Kompendium # Kompendium
[![version](https://img.shields.io/maven-central/v/io.bkbn/kompendium-core?style=flat-square)](https://search.maven.org/search?q=io.bkbn%20kompendium)
## What is Kompendium ## What is Kompendium
Kompendium is intended to be a minimally invasive OpenApi Specification generator for [Ktor](https://ktor.io). Kompendium is intended to be a minimally invasive OpenApi Specification generator for [Ktor](https://ktor.io).
@ -8,8 +10,26 @@ supplement with Kompendium code in order to generate the appropriate spec.
## How to install ## How to install
Kompendium uses GitHub packages as its repository. Installing with Gradle is pretty painless. In your `build.gradle.kts` Kompendium publishes all releases to Maven Central. As such, using the stable version of `Kompendium` is as simple
add the following as declaring it as an implementation dependency in your `build.gradle.kts`
```kotlin
repositories {
mavenCentral()
}
dependencies {
// other (less cool) dependencies
implementation("io.bkbn:kompendium-core:latest")
implementation("io.bkbn:kompendium-auth:latest")
implementation("io.bkbn:kompendium-swagger-ui:latest")
}
```
The last two dependencies are optional.
If you want to get a little spicy 🤠 every merge of Kompendium is published to the GitHub package registry. Pulling
from GitHub is slightly more involved, but such is the price you pay for bleeding edge fake data generation.
```kotlin ```kotlin
// 1 Setup a helper function to import any Github Repository Package // 1 Setup a helper function to import any Github Repository Package
@ -17,7 +37,7 @@ add the following
fun RepositoryHandler.github(packageUrl: String) = maven { fun RepositoryHandler.github(packageUrl: String) = maven {
name = "GithubPackages" name = "GithubPackages"
url = uri(packageUrl) url = uri(packageUrl)
credentials { // TODO Not sure this is necessary for public repositories? credentials {
username = java.lang.System.getenv("GITHUB_USER") username = java.lang.System.getenv("GITHUB_USER")
password = java.lang.System.getenv("GITHUB_TOKEN") password = java.lang.System.getenv("GITHUB_TOKEN")
} }
@ -25,12 +45,12 @@ fun RepositoryHandler.github(packageUrl: String) = maven {
// 2 Add the repo in question (in this case Kompendium) // 2 Add the repo in question (in this case Kompendium)
repositories { repositories {
github("https://maven.pkg.github.com/lg-backbone/kompendium") github("https://maven.pkg.github.com/bkbnio/kompendium")
} }
// 3 Add the package like any normal dependency // 3 Add the package like any normal dependency
dependencies { dependencies {
implementation("org.leafygreens:kompendium-core:0.1.0-SNAPSHOT") implementation("io.bkbn:kompendium-core:1.0.0")
} }
``` ```
@ -76,6 +96,17 @@ The intended purpose of `KompendiumField` is to offer field level overrides such
The purpose of `KompendiumParam` is to provide supplemental information needed to properly assign the type of parameter The purpose of `KompendiumParam` is to provide supplemental information needed to properly assign the type of parameter
(cookie, header, query, path) as well as other parameter-level metadata. (cookie, header, query, path) as well as other parameter-level metadata.
### Polymorphism
Out of the box, Kompendium has support for sealed classes. At runtime, it will build a mapping of all available sub-classes
and build a spec that takes `anyOf` the implementations. This is currently a weak point of the entire library, and
suggestions on better implementations are welcome 🤠
### Serialization
Under the hood, Kompendium uses Jackson to serialize the final api spec. However, this implementation detail
does not leak to the actual API, meaning that users are free to choose the serialization library of their choice.
## Examples ## Examples
The full source code can be found in the `kompendium-playground` module. Here is a simple get endpoint example The full source code can be found in the `kompendium-playground` module. Here is a simple get endpoint example
@ -199,12 +230,11 @@ If this is a blocker, please open a GitHub issue, and we can start to think out
Work on V1 of Kompendium has come to a close. This, however, does not mean it has achieved complete Work on V1 of Kompendium has come to a close. This, however, does not mean it has achieved complete
parity with the OpenAPI feature spec, nor does it have all-of-the nice to have features that a truly next-gen API spec parity with the OpenAPI feature spec, nor does it have all-of-the nice to have features that a truly next-gen API spec
should have. There are several outstanding features that have been added to the should have. There are several outstanding features that have been added to the
[V2 Milestone](https://github.com/lg-backbone/kompendium/milestone/2). Among others, this includes [V2 Milestone](https://github.com/bkbnio/kompendium/milestone/2). Among others, this includes
- Polymorphic support
- AsyncAPI Integration - AsyncAPI Integration
- Field Validation - Field Validation
- MavenCentral Release - MavenCentral Release
If you have a feature that you would like to see implemented that is not on this list, or discover a 🐞, please open If you have a feature that you would like to see implemented that is not on this list, or discover a 🐞, please open
an issue [here](https://github.com/lg-backbone/kompendium/issues/new) an issue [here](https://github.com/bkbnio/kompendium/issues/new)

View File

@ -1,14 +1,20 @@
import com.adarshr.gradle.testlogger.TestLoggerExtension
import com.adarshr.gradle.testlogger.theme.ThemeType
import io.gitlab.arturbosch.detekt.extensions.DetektExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
id("org.jetbrains.kotlin.jvm") version "1.4.32" apply false id("org.jetbrains.kotlin.jvm") version "1.5.0" apply false
id("io.gitlab.arturbosch.detekt") version "1.16.0-RC2" apply false id("io.gitlab.arturbosch.detekt") version "1.17.0-RC3" apply false
id("com.adarshr.test-logger") version "3.0.0" apply false id("com.adarshr.test-logger") version "3.0.0" apply false
id("io.github.gradle-nexus.publish-plugin") version "1.1.0" apply true
} }
allprojects { allprojects {
group = "org.leafygreens" group = "io.bkbn"
version = run { version = run {
val baseVersion = val baseVersion =
project.findProperty("project.version") ?: error("project.version must be set in gradle.properties") project.findProperty("project.version") ?: error("project.version needs to be set in gradle.properties")
when ((project.findProperty("release") as? String)?.toBoolean()) { when ((project.findProperty("release") as? String)?.toBoolean()) {
true -> baseVersion true -> baseVersion
else -> "$baseVersion-SNAPSHOT" else -> "$baseVersion-SNAPSHOT"
@ -25,14 +31,14 @@ allprojects {
apply(plugin = "com.adarshr.test-logger") apply(plugin = "com.adarshr.test-logger")
apply(plugin = "idea") apply(plugin = "idea")
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach { tasks.withType<KotlinCompile>().configureEach {
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = "1.8"
} }
} }
configure<com.adarshr.gradle.testlogger.TestLoggerExtension> { configure<TestLoggerExtension> {
setTheme("standard") theme = ThemeType.MOCHA
setLogLevel("lifecycle") setLogLevel("lifecycle")
showExceptions = true showExceptions = true
showStackTraces = true showStackTraces = true
@ -50,13 +56,23 @@ allprojects {
showFailedStandardStreams = true showFailedStandardStreams = true
} }
configure<io.gitlab.arturbosch.detekt.extensions.DetektExtension> { configure<DetektExtension> {
toolVersion = "1.16.0-RC2" toolVersion = "1.17.0-RC3"
config = files("${rootProject.projectDir}/detekt.yml") config = files("${rootProject.projectDir}/detekt.yml")
buildUponDefaultConfig = true buildUponDefaultConfig = true
} }
configure<JavaPluginExtension> { configure<JavaPluginExtension> {
withSourcesJar() withSourcesJar()
withJavadocJar()
}
}
nexusPublishing {
repositories {
sonatype {
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
}
} }
} }

View File

@ -1,5 +1,5 @@
# Kompendium # Kompendium
project.version=1.0.0-beta project.version=1.5.0
# Kotlin # Kotlin
kotlin.code.style=official kotlin.code.style=official
# Gradle # Gradle

View File

@ -1,6 +1,8 @@
[versions] [versions]
kotlin = "1.4.32" kotlin = "1.4.32"
ktor = "1.5.3" ktor = "1.5.3"
kotlinx-serialization = "1.2.1"
jackson-kotlin = "2.12.0"
slf4j = "1.7.30" slf4j = "1.7.30"
logback = "1.2.3" logback = "1.2.3"
swagger-ui = "3.47.1" swagger-ui = "3.47.1"
@ -10,11 +12,17 @@ swagger-ui = "3.47.1"
ktor-server-core = { group = "io.ktor", name = "ktor-server-core", version.ref = "ktor" } ktor-server-core = { group = "io.ktor", name = "ktor-server-core", version.ref = "ktor" }
ktor-server-netty = { group = "io.ktor", name = "ktor-server-netty", version.ref = "ktor" } ktor-server-netty = { group = "io.ktor", name = "ktor-server-netty", version.ref = "ktor" }
ktor-jackson = { group = "io.ktor", name = "ktor-jackson", version.ref = "ktor" } ktor-jackson = { group = "io.ktor", name = "ktor-jackson", version.ref = "ktor" }
ktor-serialization = { group = "io.ktor", name = "ktor-serialization", version.ref = "ktor" }
ktor-html-builder = { group = "io.ktor", name = "ktor-html-builder", version.ref = "ktor" } ktor-html-builder = { group = "io.ktor", name = "ktor-html-builder", version.ref = "ktor" }
ktor-auth-lib = { group = "io.ktor", name = "ktor-auth", version.ref = "ktor" } ktor-auth-lib = { group = "io.ktor", name = "ktor-auth", version.ref = "ktor" }
ktor-auth-jwt = { group = "io.ktor", name = "ktor-auth-jwt", version.ref = "ktor" } ktor-auth-jwt = { group = "io.ktor", name = "ktor-auth-jwt", version.ref = "ktor" }
ktor-webjars = { group = "io.ktor", name = "ktor-webjars", version.ref = "ktor" } ktor-webjars = { group = "io.ktor", name = "ktor-webjars", version.ref = "ktor" }
# Serialization
jackson-module-kotlin = { group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version.ref = "jackson-kotlin" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
# Logging # Logging
slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" } slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" } logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
@ -23,7 +31,10 @@ logback-core = { group = "ch.qos.logback", name = "logback-core", version.ref =
# webjars # webjars
webjars-swagger-ui = { group = "org.webjars", name = "swagger-ui", version.ref = "swagger-ui" } webjars-swagger-ui = { group = "org.webjars", name = "swagger-ui", version.ref = "swagger-ui" }
# Testing
ktor-server-test-host = { group = "io.ktor", name = "ktor-server-test-host", version.ref = "ktor" }
[bundles] [bundles]
ktor = [ "ktor-server-core", "ktor-server-netty", "ktor-jackson", "ktor-html-builder" ] ktor = ["ktor-server-core", "ktor-server-netty", "ktor-html-builder"]
ktorAuth = [ "ktor-auth-lib", "ktor-auth-jwt" ] ktorAuth = ["ktor-auth-lib", "ktor-auth-jwt"]
logging = [ "slf4j", "logback-classic", "logback-core" ] logging = ["slf4j", "logback-classic", "logback-core"]

View File

@ -1,6 +1,7 @@
plugins { plugins {
`java-library` `java-library`
`maven-publish` `maven-publish`
signing
} }
dependencies { dependencies {
@ -10,21 +11,23 @@ dependencies {
implementation(libs.bundles.ktorAuth) implementation(libs.bundles.ktorAuth)
implementation(projects.kompendiumCore) implementation(projects.kompendiumCore)
testImplementation(libs.ktor.jackson)
testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit") testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.0") testImplementation(libs.jackson.module.kotlin)
testImplementation("io.ktor:ktor-server-test-host:1.5.3") testImplementation(libs.ktor.server.test.host)
} }
java { java {
withSourcesJar() withSourcesJar()
withJavadocJar()
} }
publishing { publishing {
repositories { repositories {
maven { maven {
name = "GithubPackages" name = "GithubPackages"
url = uri("https://maven.pkg.github.com/lg-backbone/kompendium") url = uri("https://maven.pkg.github.com/bkbnio/kompendium")
credentials { credentials {
username = System.getenv("GITHUB_ACTOR") username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN") password = System.getenv("GITHUB_TOKEN")
@ -35,6 +38,41 @@ publishing {
create<MavenPublication>("kompendium") { create<MavenPublication>("kompendium") {
from(components["kotlin"]) from(components["kotlin"])
artifact(tasks.sourcesJar) artifact(tasks.sourcesJar)
artifact(tasks.javadocJar)
groupId = project.group.toString()
artifactId = project.name.toLowerCase()
version = project.version.toString()
pom {
name.set("Kompendium")
description.set("A minimally invasive OpenAPI spec generator for Ktor")
url.set("https://github.com/bkbnio/Kompendium")
licenses {
license {
name.set("MIT License")
url.set("https://mit-license.org/")
}
}
developers {
developer {
id.set("bkbnio")
name.set("Ryan Brink")
email.set("admin@bkbn.io")
}
}
scm {
connection.set("scm:git:git://github.com/bkbnio/Kompendium.git")
developerConnection.set("scm:git:ssh://github.com/bkbnio/Kompendium.git")
url.set("https://github.com/bkbnio/Kompendium.git")
}
}
} }
} }
} }
signing {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
sign(publishing.publications)
}

View File

@ -1,8 +1,8 @@
package org.leafygreens.kompendium.auth package io.bkbn.kompendium.auth
import io.ktor.auth.AuthenticationRouteSelector import io.ktor.auth.AuthenticationRouteSelector
import io.ktor.routing.Route import io.ktor.routing.Route
import org.leafygreens.kompendium.path.CorePathCalculator import io.bkbn.kompendium.path.CorePathCalculator
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
class AuthPathCalculator : CorePathCalculator() { class AuthPathCalculator : CorePathCalculator() {

View File

@ -1,12 +1,12 @@
package org.leafygreens.kompendium.auth package io.bkbn.kompendium.auth
import io.ktor.auth.Authentication import io.ktor.auth.Authentication
import io.ktor.auth.basic import io.ktor.auth.basic
import io.ktor.auth.BasicAuthenticationProvider import io.ktor.auth.BasicAuthenticationProvider
import io.ktor.auth.jwt.jwt import io.ktor.auth.jwt.jwt
import io.ktor.auth.jwt.JWTAuthenticationProvider import io.ktor.auth.jwt.JWTAuthenticationProvider
import org.leafygreens.kompendium.Kompendium import io.bkbn.kompendium.Kompendium
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaSecurity import io.bkbn.kompendium.models.oas.OpenApiSpecSchemaSecurity
object KompendiumAuth { object KompendiumAuth {

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.auth package io.bkbn.kompendium.auth
import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.databind.SerializationFeature
@ -21,17 +21,17 @@ import io.ktor.server.testing.withTestApplication
import kotlin.test.AfterTest import kotlin.test.AfterTest
import kotlin.test.assertEquals import kotlin.test.assertEquals
import org.junit.Test import org.junit.Test
import org.leafygreens.kompendium.Kompendium import io.bkbn.kompendium.Kompendium
import org.leafygreens.kompendium.Notarized.notarizedGet import io.bkbn.kompendium.Notarized.notarizedGet
import org.leafygreens.kompendium.auth.KompendiumAuth.notarizedBasic import io.bkbn.kompendium.auth.KompendiumAuth.notarizedBasic
import org.leafygreens.kompendium.auth.KompendiumAuth.notarizedJwt import io.bkbn.kompendium.auth.KompendiumAuth.notarizedJwt
import org.leafygreens.kompendium.auth.util.TestData import io.bkbn.kompendium.auth.util.TestData
import org.leafygreens.kompendium.auth.util.TestParams import io.bkbn.kompendium.auth.util.TestParams
import org.leafygreens.kompendium.auth.util.TestResponse import io.bkbn.kompendium.auth.util.TestResponse
import org.leafygreens.kompendium.models.meta.MethodInfo import io.bkbn.kompendium.models.meta.MethodInfo
import org.leafygreens.kompendium.models.meta.ResponseInfo import io.bkbn.kompendium.models.meta.ResponseInfo
import org.leafygreens.kompendium.routes.openApi import io.bkbn.kompendium.routes.openApi
import org.leafygreens.kompendium.routes.redoc import io.bkbn.kompendium.routes.redoc
internal class KompendiumAuthTest { internal class KompendiumAuthTest {

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.auth.util package io.bkbn.kompendium.auth.util
import java.io.File import java.io.File

View File

@ -1,8 +1,8 @@
package org.leafygreens.kompendium.auth.util package io.bkbn.kompendium.auth.util
import org.leafygreens.kompendium.annotations.KompendiumField import io.bkbn.kompendium.annotations.KompendiumField
import org.leafygreens.kompendium.annotations.KompendiumParam import io.bkbn.kompendium.annotations.KompendiumParam
import org.leafygreens.kompendium.annotations.ParamType import io.bkbn.kompendium.annotations.ParamType
data class TestParams( data class TestParams(
@KompendiumParam(ParamType.PATH) val a: String, @KompendiumParam(ParamType.PATH) val a: String,

View File

@ -20,8 +20,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -51,16 +51,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { "securitySchemes" : {

View File

@ -20,8 +20,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -51,16 +51,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { "securitySchemes" : {

View File

@ -20,8 +20,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -51,16 +51,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { "securitySchemes" : {

View File

@ -20,8 +20,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -51,16 +51,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { "securitySchemes" : {

View File

@ -20,8 +20,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -52,16 +52,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { "securitySchemes" : {

View File

@ -1,27 +1,32 @@
plugins { plugins {
`java-library` `java-library`
`maven-publish` `maven-publish`
signing
} }
dependencies { dependencies {
implementation(platform("org.jetbrains.kotlin:kotlin-bom")) implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation(libs.jackson.module.kotlin)
implementation(libs.bundles.ktor) implementation(libs.bundles.ktor)
testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit") testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.0") testImplementation(libs.ktor.serialization)
testImplementation("io.ktor:ktor-server-test-host:1.5.3") testImplementation(libs.kotlinx.serialization.json)
testImplementation(libs.ktor.jackson)
testImplementation(libs.ktor.server.test.host)
} }
java { java {
withSourcesJar() withSourcesJar()
withJavadocJar()
} }
publishing { publishing {
repositories { repositories {
maven { maven {
name = "GithubPackages" name = "GithubPackages"
url = uri("https://maven.pkg.github.com/lg-backbone/kompendium") url = uri("https://maven.pkg.github.com/bkbnio/kompendium")
credentials { credentials {
username = System.getenv("GITHUB_ACTOR") username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN") password = System.getenv("GITHUB_TOKEN")
@ -32,6 +37,41 @@ publishing {
create<MavenPublication>("kompendium") { create<MavenPublication>("kompendium") {
from(components["kotlin"]) from(components["kotlin"])
artifact(tasks.sourcesJar) artifact(tasks.sourcesJar)
artifact(tasks.javadocJar)
groupId = project.group.toString()
artifactId = project.name.toLowerCase()
version = project.version.toString()
pom {
name.set("Kompendium")
description.set("A minimally invasive OpenAPI spec generator for Ktor")
url.set("https://github.com/bkbnio/Kompendium")
licenses {
license {
name.set("MIT License")
url.set("https://mit-license.org/")
}
}
developers {
developer {
id.set("bkbnio")
name.set("Ryan Brink")
email.set("admin@bkbn.io")
}
}
scm {
connection.set("scm:git:git://github.com/bkbnio/Kompendium.git")
developerConnection.set("scm:git:ssh://github.com/bkbnio/Kompendium.git")
url.set("https://github.com/bkbnio/Kompendium.git")
}
}
} }
} }
} }
signing {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
sign(publishing.publications)
}

View File

@ -1,11 +1,11 @@
package org.leafygreens.kompendium package io.bkbn.kompendium
import org.leafygreens.kompendium.models.meta.ErrorMap import io.bkbn.kompendium.models.meta.ErrorMap
import org.leafygreens.kompendium.models.meta.SchemaMap import io.bkbn.kompendium.models.meta.SchemaMap
import org.leafygreens.kompendium.models.oas.OpenApiSpec import io.bkbn.kompendium.models.oas.OpenApiSpec
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo import io.bkbn.kompendium.models.oas.OpenApiSpecInfo
import org.leafygreens.kompendium.path.CorePathCalculator import io.bkbn.kompendium.path.CorePathCalculator
import org.leafygreens.kompendium.path.PathCalculator import io.bkbn.kompendium.path.PathCalculator
/** /**
* Maintains all state for the Kompendium library * Maintains all state for the Kompendium library

View File

@ -1,7 +1,9 @@
package org.leafygreens.kompendium package io.bkbn.kompendium
import io.ktor.routing.Route import io.ktor.routing.Route
import kotlin.reflect.KClass
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.full.createType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
/** /**
@ -21,13 +23,11 @@ object KompendiumPreFlight {
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> methodNotarizationPreFlight( inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> methodNotarizationPreFlight(
block: (KType, KType, KType) -> Route block: (KType, KType, KType) -> Route
): Route { ): Route {
Kompendium.cache = Kontent.generateKontent<TResp>(Kompendium.cache)
Kompendium.cache = Kontent.generateKontent<TReq>(Kompendium.cache)
Kompendium.cache = Kontent.generateParameterKontent<TParam>(Kompendium.cache)
Kompendium.openApiSpec.components.schemas.putAll(Kompendium.cache)
val requestType = typeOf<TReq>() val requestType = typeOf<TReq>()
val responseType = typeOf<TResp>() val responseType = typeOf<TResp>()
val paramType = typeOf<TParam>() val paramType = typeOf<TParam>()
addToCache(paramType, requestType, responseType)
Kompendium.openApiSpec.components.schemas.putAll(Kompendium.cache)
return block.invoke(paramType, requestType, responseType) return block.invoke(paramType, requestType, responseType)
} }
@ -38,13 +38,34 @@ object KompendiumPreFlight {
* @param block The function to execute, provided type information of the parameters above * @param block The function to execute, provided type information of the parameters above
*/ */
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
inline fun <reified TErr: Throwable, reified TResp : Any> errorNotarizationPreFlight( inline fun <reified TErr : Throwable, reified TResp : Any> errorNotarizationPreFlight(
block: (KType, KType) -> Unit block: (KType, KType) -> Unit
) { ) {
Kompendium.cache = Kontent.generateKontent<TResp>(Kompendium.cache)
Kompendium.openApiSpec.components.schemas.putAll(Kompendium.cache)
val errorType = typeOf<TErr>() val errorType = typeOf<TErr>()
val responseType = typeOf<TResp>() val responseType = typeOf<TResp>()
addToCache(typeOf<Unit>(), typeOf<Unit>(), responseType)
Kompendium.openApiSpec.components.schemas.putAll(Kompendium.cache)
return block.invoke(errorType, responseType) return block.invoke(errorType, responseType)
} }
fun addToCache(paramType: KType, requestType: KType, responseType: KType) {
gatherSubTypes(requestType).forEach {
Kompendium.cache = Kontent.generateKontent(it, Kompendium.cache)
}
gatherSubTypes(responseType).forEach {
Kompendium.cache = Kontent.generateKontent(it, Kompendium.cache)
}
Kompendium.cache = Kontent.generateParameterKontent(paramType, Kompendium.cache)
}
private fun gatherSubTypes(type: KType): List<KType> {
val classifier = type.classifier as KClass<*>
return if (classifier.isSealed) {
classifier.sealedSubclasses.map {
it.createType(type.arguments)
}
} else {
listOf(type)
}
}
} }

View File

@ -1,25 +1,30 @@
package org.leafygreens.kompendium package io.bkbn.kompendium
import io.bkbn.kompendium.models.meta.SchemaMap
import io.bkbn.kompendium.models.oas.AnyOfReferencedSchema
import io.bkbn.kompendium.models.oas.ArraySchema
import io.bkbn.kompendium.models.oas.DictionarySchema
import io.bkbn.kompendium.models.oas.EnumSchema
import io.bkbn.kompendium.models.oas.FormatSchema
import io.bkbn.kompendium.models.oas.ObjectSchema
import io.bkbn.kompendium.models.oas.ReferencedSchema
import io.bkbn.kompendium.models.oas.SimpleSchema
import io.bkbn.kompendium.util.Helpers.COMPONENT_SLUG
import io.bkbn.kompendium.util.Helpers.genericNameAdapter
import io.bkbn.kompendium.util.Helpers.getReferenceSlug
import io.bkbn.kompendium.util.Helpers.getSimpleSlug
import io.bkbn.kompendium.util.Helpers.logged
import java.util.UUID import java.util.UUID
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.full.createType
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.memberProperties import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaField import kotlin.reflect.jvm.javaField
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
import org.leafygreens.kompendium.models.meta.SchemaMap
import org.leafygreens.kompendium.models.oas.ArraySchema
import org.leafygreens.kompendium.models.oas.DictionarySchema
import org.leafygreens.kompendium.models.oas.EnumSchema
import org.leafygreens.kompendium.models.oas.FormatSchema
import org.leafygreens.kompendium.models.oas.ObjectSchema
import org.leafygreens.kompendium.models.oas.ReferencedSchema
import org.leafygreens.kompendium.models.oas.SimpleSchema
import org.leafygreens.kompendium.util.Helpers.COMPONENT_SLUG
import org.leafygreens.kompendium.util.Helpers.genericNameAdapter
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
import org.leafygreens.kompendium.util.Helpers.logged
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.math.BigDecimal
import java.math.BigInteger
/** /**
* Responsible for generating the schema map that is used to power all object references across the API Spec. * Responsible for generating the schema map that is used to power all object references across the API Spec.
@ -42,6 +47,19 @@ object Kontent {
return generateKTypeKontent(kontentType, cache) return generateKTypeKontent(kontentType, cache)
} }
/**
* Analyzes a [KType] for its top-level and any nested schemas, and adds them to a [SchemaMap], if provided
* @param type [KType] to analyze
* @param cache Existing schema map to append to
* @return an updated schema map containing all type information for [KType] type
*/
fun generateKontent(
type: KType,
cache: SchemaMap = emptyMap()
): SchemaMap {
return generateKTypeKontent(type, cache)
}
/** /**
* Analyze a type [T], but filters out the top-level type * Analyze a type [T], but filters out the top-level type
* @param T type to analyze * @param T type to analyze
@ -57,6 +75,20 @@ object Kontent {
.filterNot { (slug, _) -> slug == (kontentType.classifier as KClass<*>).simpleName } .filterNot { (slug, _) -> slug == (kontentType.classifier as KClass<*>).simpleName }
} }
/**
* Analyze a type but filters out the top-level type
* @param type to analyze
* @param cache Existing schema map to append to
* @return an updated schema map containing all type information for [T]
*/
fun generateParameterKontent(
type: KType,
cache: SchemaMap = emptyMap()
): SchemaMap {
return generateKTypeKontent(type, cache)
.filterNot { (slug, _) -> slug == (type.classifier as KClass<*>).simpleName }
}
/** /**
* Recursively fills schema map depending on [KType] classifier * Recursively fills schema map depending on [KType] classifier
* @param type [KType] to parse * @param type [KType] to parse
@ -76,11 +108,13 @@ object Kontent {
String::class -> cache.plus(clazz.simpleName!! to SimpleSchema("string")) String::class -> cache.plus(clazz.simpleName!! to SimpleSchema("string"))
Boolean::class -> cache.plus(clazz.simpleName!! to SimpleSchema("boolean")) Boolean::class -> cache.plus(clazz.simpleName!! to SimpleSchema("boolean"))
UUID::class -> cache.plus(clazz.simpleName!! to FormatSchema("uuid", "string")) UUID::class -> cache.plus(clazz.simpleName!! to FormatSchema("uuid", "string"))
BigDecimal::class -> cache.plus(clazz.simpleName!! to FormatSchema("double", "number"))
BigInteger::class -> cache.plus(clazz.simpleName!! to FormatSchema("int64", "integer"))
else -> when { else -> when {
clazz.isSubclassOf(Collection::class) -> handleCollectionType(type, clazz, cache) clazz.isSubclassOf(Collection::class) -> handleCollectionType(type, clazz, cache)
clazz.isSubclassOf(Enum::class) -> handleEnumType(clazz, cache) clazz.isSubclassOf(Enum::class) -> handleEnumType(clazz, cache)
clazz.isSubclassOf(Map::class) -> handleMapType(type, clazz, cache) clazz.isSubclassOf(Map::class) -> handleMapType(type, clazz, cache)
else -> handleComplexType(clazz, cache) else -> handleComplexType(type, clazz, cache)
} }
} }
} }
@ -90,30 +124,76 @@ object Kontent {
* @param clazz Class of the object to analyze * @param clazz Class of the object to analyze
* @param cache Existing schema map to append to * @param cache Existing schema map to append to
*/ */
private fun handleComplexType(clazz: KClass<*>, cache: SchemaMap): SchemaMap = private fun handleComplexType(type: KType, clazz: KClass<*>, cache: SchemaMap): SchemaMap {
when (cache.containsKey(clazz.simpleName)) { // This needs to be simple because it will be stored under it's appropriate reference component implicitly
val slug = type.getSimpleSlug()
// Only analyze if component has not already been stored in the cache
return when (cache.containsKey(slug)) {
true -> { true -> {
logger.debug("Cache already contains ${clazz.simpleName}, returning cache untouched") logger.debug("Cache already contains $slug, returning cache untouched")
cache cache
} }
false -> { false -> {
logger.debug("${clazz.simpleName} was not found in cache, generating now") logger.debug("$slug was not found in cache, generating now")
var newCache = cache var newCache = cache
// Grabs any type parameters as a zip with the corresponding type argument
val typeMap = clazz.typeParameters.zip(type.arguments).toMap()
// associates each member with a Pair of prop name to property schema
val fieldMap = clazz.memberProperties.associate { prop -> val fieldMap = clazz.memberProperties.associate { prop ->
logger.debug("Analyzing $prop in class $clazz") logger.debug("Analyzing $prop in class $clazz")
// Grab the field of the current property
val field = prop.javaField?.type?.kotlin ?: error("Unable to parse field type from $prop") val field = prop.javaField?.type?.kotlin ?: error("Unable to parse field type from $prop")
logger.debug("Detected field $field") logger.debug("Detected field $field")
// Yoinks any generic types from the type map should the field be a generic
val yoinkBaseType = if (typeMap.containsKey(prop.returnType.classifier)) {
logger.debug("Generic type detected")
typeMap[prop.returnType.classifier]?.type!!
} else {
prop.returnType
}
// converts the base type to a class
val yoinkedClassifier = yoinkBaseType.classifier as KClass<*>
// in the event of a sealed class, grab all sealed subclasses and create a type from the base args
val yoinkedTypes = if (yoinkedClassifier.isSealed) {
yoinkedClassifier.sealedSubclasses.map { it.createType(yoinkBaseType.arguments) }
} else {
listOf(yoinkBaseType)
}
// if the most up-to-date cache does not contain the content for this field, generate it and add to cache
if (!newCache.containsKey(field.simpleName)) { if (!newCache.containsKey(field.simpleName)) {
logger.debug("Cache was missing ${field.simpleName}, adding now") logger.debug("Cache was missing ${field.simpleName}, adding now")
newCache = generateKTypeKontent(prop.returnType, newCache) yoinkedTypes.forEach {
newCache = generateKTypeKontent(it, newCache)
}
}
// TODO This in particular is worthy of a refactor... just not very well written
// builds the appropriate property schema based on the property return type
val propSchema = if (typeMap.containsKey(prop.returnType.classifier)) {
if (yoinkedClassifier.isSealed) {
val refs = yoinkedClassifier.sealedSubclasses
.map { it.createType(yoinkBaseType.arguments) }
.map { ReferencedSchema(it.getReferenceSlug()) }
AnyOfReferencedSchema(refs)
} else {
ReferencedSchema(typeMap[prop.returnType.classifier]?.type!!.getReferenceSlug())
}
} else {
if (yoinkedClassifier.isSealed) {
val refs = yoinkedClassifier.sealedSubclasses
.map { it.createType(yoinkBaseType.arguments) }
.map { ReferencedSchema(it.getReferenceSlug()) }
AnyOfReferencedSchema(refs)
} else {
ReferencedSchema(field.getReferenceSlug(prop))
}
} }
val propSchema = ReferencedSchema(field.getReferenceSlug(prop))
Pair(prop.name, propSchema) Pair(prop.name, propSchema)
} }
logger.debug("${clazz.simpleName} contains $fieldMap") logger.debug("$slug contains $fieldMap")
val schema = ObjectSchema(fieldMap) val schema = ObjectSchema(fieldMap)
logger.debug("${clazz.simpleName} schema: $schema") logger.debug("$slug schema: $schema")
newCache.plus(clazz.simpleName!! to schema) newCache.plus(slug to schema)
}
} }
} }

View File

@ -1,5 +1,22 @@
package org.leafygreens.kompendium package io.bkbn.kompendium
import io.bkbn.kompendium.annotations.KompendiumParam
import io.bkbn.kompendium.models.meta.MethodInfo
import io.bkbn.kompendium.models.meta.RequestInfo
import io.bkbn.kompendium.models.meta.ResponseInfo
import io.bkbn.kompendium.models.oas.ExampleWrapper
import io.bkbn.kompendium.models.oas.OpenApiAnyOf
import io.bkbn.kompendium.models.oas.OpenApiSpecMediaType
import io.bkbn.kompendium.models.oas.OpenApiSpecParameter
import io.bkbn.kompendium.models.oas.OpenApiSpecPathItemOperation
import io.bkbn.kompendium.models.oas.OpenApiSpecReferencable
import io.bkbn.kompendium.models.oas.OpenApiSpecReferenceObject
import io.bkbn.kompendium.models.oas.OpenApiSpecRequest
import io.bkbn.kompendium.models.oas.OpenApiSpecResponse
import io.bkbn.kompendium.util.Helpers
import io.bkbn.kompendium.util.Helpers.getReferenceSlug
import io.bkbn.kompendium.util.Helpers.getSimpleSlug
import java.util.Locale
import java.util.UUID import java.util.UUID
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.KParameter import kotlin.reflect.KParameter
@ -10,21 +27,6 @@ import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.primaryConstructor import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.jvm.javaField import kotlin.reflect.jvm.javaField
import org.leafygreens.kompendium.annotations.KompendiumParam
import org.leafygreens.kompendium.models.meta.MethodInfo
import org.leafygreens.kompendium.models.meta.RequestInfo
import org.leafygreens.kompendium.models.meta.ResponseInfo
import org.leafygreens.kompendium.models.oas.ExampleWrapper
import org.leafygreens.kompendium.models.oas.OpenApiSpecMediaType
import org.leafygreens.kompendium.models.oas.OpenApiSpecParameter
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItemOperation
import org.leafygreens.kompendium.models.oas.OpenApiSpecReferencable
import org.leafygreens.kompendium.models.oas.OpenApiSpecReferenceObject
import org.leafygreens.kompendium.models.oas.OpenApiSpecRequest
import org.leafygreens.kompendium.models.oas.OpenApiSpecResponse
import org.leafygreens.kompendium.util.Helpers
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
import org.leafygreens.kompendium.util.Helpers.getSimpleSlug
/** /**
* The MethodParser is responsible for converting route metadata and types into an OpenAPI compatible data class. * The MethodParser is responsible for converting route metadata and types into an OpenAPI compatible data class.
@ -106,7 +108,7 @@ object MethodParser {
else -> { else -> {
OpenApiSpecRequest( OpenApiSpecRequest(
description = requestInfo.description, description = requestInfo.description,
content = resolveContent(requestInfo.mediaTypes, requestInfo.examples) ?: mapOf() content = resolveContent(this, requestInfo.mediaTypes, requestInfo.examples) ?: mapOf()
) )
} }
} }
@ -123,7 +125,7 @@ object MethodParser {
else -> { else -> {
val specResponse = OpenApiSpecResponse( val specResponse = OpenApiSpecResponse(
description = responseInfo.description, description = responseInfo.description,
content = resolveContent(responseInfo.mediaTypes, responseInfo.examples) content = resolveContent(this, responseInfo.mediaTypes, responseInfo.examples)
) )
Pair(responseInfo.status.value, specResponse) Pair(responseInfo.status.value, specResponse)
} }
@ -131,20 +133,31 @@ object MethodParser {
/** /**
* Generates MediaTypes along with any examples provided * Generates MediaTypes along with any examples provided
* @receiver [KType] Type of the object * @param type [KType] Type of the object
* @param mediaTypes list of acceptable http media types * @param mediaTypes list of acceptable http media types
* @param examples Mapping of named examples of valid bodies. * @param examples Mapping of named examples of valid bodies.
* @return Named mapping of media types. * @return Named mapping of media types.
*/ */
private fun <F> KType.resolveContent( private fun <F> resolveContent(
type: KType,
mediaTypes: List<String>, mediaTypes: List<String>,
examples: Map<String, F> examples: Map<String, F>
): Map<String, OpenApiSpecMediaType<F>>? { ): Map<String, OpenApiSpecMediaType<F>>? {
return if (this != Helpers.UNIT_TYPE && mediaTypes.isNotEmpty()) { val classifier = type.classifier as KClass<*>
return if (type != Helpers.UNIT_TYPE && mediaTypes.isNotEmpty()) {
mediaTypes.associateWith { mediaTypes.associateWith {
val ref = getReferenceSlug() val schema = if (classifier.isSealed) {
val refs = classifier.sealedSubclasses
.map { it.createType(type.arguments) }
.map { it.getReferenceSlug() }
.map { OpenApiSpecReferenceObject(it) }
OpenApiAnyOf(refs)
} else {
val ref = type.getReferenceSlug()
OpenApiSpecReferenceObject(ref)
}
OpenApiSpecMediaType( OpenApiSpecMediaType(
schema = OpenApiSpecReferenceObject(ref), schema = schema,
examples = examples.mapValues { (_, v) -> ExampleWrapper(v) }.ifEmpty { null } examples = examples.mapValues { (_, v) -> ExampleWrapper(v) }.ifEmpty { null }
) )
} }
@ -153,7 +166,7 @@ object MethodParser {
/** /**
* Parses a type for all parameter information. All fields in the receiver * Parses a type for all parameter information. All fields in the receiver
* must be annotated with [org.leafygreens.kompendium.annotations.KompendiumParam]. * must be annotated with [io.bkbn.kompendium.annotations.KompendiumParam].
* @receiver type * @receiver type
* @return list of valid parameter specs as detailed by the [KType] members * @return list of valid parameter specs as detailed by the [KType] members
* @throws [IllegalStateException] if the class could not be parsed properly * @throws [IllegalStateException] if the class could not be parsed properly
@ -170,7 +183,7 @@ object MethodParser {
val defaultValue = getDefaultParameterValue(clazz, prop) val defaultValue = getDefaultParameterValue(clazz, prop)
OpenApiSpecParameter( OpenApiSpecParameter(
name = prop.name, name = prop.name,
`in` = anny.type.name.toLowerCase(), `in` = anny.type.name.lowercase(Locale.getDefault()),
schema = schema.addDefault(defaultValue), schema = schema.addDefault(defaultValue),
description = anny.description.ifBlank { null }, description = anny.description.ifBlank { null },
required = !prop.returnType.isMarkedNullable required = !prop.returnType.isMarkedNullable

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium package io.bkbn.kompendium
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
import io.ktor.features.StatusPages import io.ktor.features.StatusPages
@ -7,15 +7,15 @@ import io.ktor.routing.Route
import io.ktor.routing.method import io.ktor.routing.method
import io.ktor.util.pipeline.PipelineContext import io.ktor.util.pipeline.PipelineContext
import io.ktor.util.pipeline.PipelineInterceptor import io.ktor.util.pipeline.PipelineInterceptor
import org.leafygreens.kompendium.KompendiumPreFlight.errorNotarizationPreFlight import io.bkbn.kompendium.KompendiumPreFlight.errorNotarizationPreFlight
import org.leafygreens.kompendium.MethodParser.parseErrorInfo import io.bkbn.kompendium.MethodParser.parseErrorInfo
import org.leafygreens.kompendium.MethodParser.parseMethodInfo import io.bkbn.kompendium.MethodParser.parseMethodInfo
import org.leafygreens.kompendium.models.meta.MethodInfo.GetInfo import io.bkbn.kompendium.models.meta.MethodInfo.GetInfo
import org.leafygreens.kompendium.models.meta.MethodInfo.PostInfo import io.bkbn.kompendium.models.meta.MethodInfo.PostInfo
import org.leafygreens.kompendium.models.meta.MethodInfo.PutInfo import io.bkbn.kompendium.models.meta.MethodInfo.PutInfo
import org.leafygreens.kompendium.models.meta.MethodInfo.DeleteInfo import io.bkbn.kompendium.models.meta.MethodInfo.DeleteInfo
import org.leafygreens.kompendium.models.meta.ResponseInfo import io.bkbn.kompendium.models.meta.ResponseInfo
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItem import io.bkbn.kompendium.models.oas.OpenApiSpecPathItem
/** /**
* Notarization methods are the primary way that a Ktor API using Kompendium differentiates * Notarization methods are the primary way that a Ktor API using Kompendium differentiates
@ -27,7 +27,7 @@ object Notarized {
/** /**
* Notarization for an HTTP GET request * Notarization for an HTTP GET request
* @param TParam The class containing all parameter fields. * @param TParam The class containing all parameter fields.
* Each field must be annotated with @[org.leafygreens.kompendium.annotations.KompendiumField] * Each field must be annotated with @[io.bkbn.kompendium.annotations.KompendiumField]
* @param TResp Class detailing the expected API response * @param TResp Class detailing the expected API response
* @param info Route metadata * @param info Route metadata
*/ */
@ -45,7 +45,7 @@ object Notarized {
/** /**
* Notarization for an HTTP POST request * Notarization for an HTTP POST request
* @param TParam The class containing all parameter fields. * @param TParam The class containing all parameter fields.
* Each field must be annotated with @[org.leafygreens.kompendium.annotations.KompendiumField] * Each field must be annotated with @[io.bkbn.kompendium.annotations.KompendiumField]
* @param TReq Class detailing the expected API request body * @param TReq Class detailing the expected API request body
* @param TResp Class detailing the expected API response * @param TResp Class detailing the expected API response
* @param info Route metadata * @param info Route metadata
@ -64,7 +64,7 @@ object Notarized {
/** /**
* Notarization for an HTTP Delete request * Notarization for an HTTP Delete request
* @param TParam The class containing all parameter fields. * @param TParam The class containing all parameter fields.
* Each field must be annotated with @[org.leafygreens.kompendium.annotations.KompendiumField] * Each field must be annotated with @[io.bkbn.kompendium.annotations.KompendiumField]
* @param TReq Class detailing the expected API request body * @param TReq Class detailing the expected API request body
* @param TResp Class detailing the expected API response * @param TResp Class detailing the expected API response
* @param info Route metadata * @param info Route metadata
@ -84,7 +84,7 @@ object Notarized {
/** /**
* Notarization for an HTTP POST request * Notarization for an HTTP POST request
* @param TParam The class containing all parameter fields. * @param TParam The class containing all parameter fields.
* Each field must be annotated with @[org.leafygreens.kompendium.annotations.KompendiumField] * Each field must be annotated with @[io.bkbn.kompendium.annotations.KompendiumField]
* @param TResp Class detailing the expected API response * @param TResp Class detailing the expected API response
* @param info Route metadata * @param info Route metadata
*/ */

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.annotations package io.bkbn.kompendium.annotations
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY) @Target(AnnotationTarget.PROPERTY)

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.annotations package io.bkbn.kompendium.annotations
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY) @Target(AnnotationTarget.PROPERTY)

View File

@ -0,0 +1,6 @@
package io.bkbn.kompendium.models.meta
import kotlin.reflect.KType
import io.bkbn.kompendium.models.oas.OpenApiSpecResponse
typealias ErrorMap = Map<KType, Pair<Int, OpenApiSpecResponse<*>>?>

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.meta package io.bkbn.kompendium.models.meta
import kotlin.reflect.KClass import kotlin.reflect.KClass

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.meta package io.bkbn.kompendium.models.meta
data class RequestInfo<TReq>( data class RequestInfo<TReq>(
val description: String, val description: String,

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.meta package io.bkbn.kompendium.models.meta
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode

View File

@ -0,0 +1,5 @@
package io.bkbn.kompendium.models.meta
import io.bkbn.kompendium.models.oas.OpenApiSpecComponentSchema
typealias SchemaMap = Map<String, OpenApiSpecComponentSchema>

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpec( data class OpenApiSpec(
val openapi: String = "3.0.3", val openapi: String = "3.0.3",

View File

@ -1,8 +1,9 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
sealed class OpenApiSpecComponentSchema(open val default: Any? = null) { sealed class OpenApiSpecComponentSchema(open val default: Any? = null) {
fun addDefault(default: Any?): OpenApiSpecComponentSchema = when (this) { fun addDefault(default: Any?): OpenApiSpecComponentSchema = when (this) {
is AnyOfReferencedSchema -> error("Cannot add default to anyOf reference")
is ReferencedSchema -> this.copy(default = default) is ReferencedSchema -> this.copy(default = default)
is ObjectSchema -> this.copy(default = default) is ObjectSchema -> this.copy(default = default)
is DictionarySchema -> this.copy(default = default) is DictionarySchema -> this.copy(default = default)
@ -17,6 +18,7 @@ sealed class OpenApiSpecComponentSchema(open val default: Any? = null) {
sealed class TypedSchema(open val type: String, override val default: Any? = null) : OpenApiSpecComponentSchema(default) sealed class TypedSchema(open val type: String, override val default: Any? = null) : OpenApiSpecComponentSchema(default)
data class ReferencedSchema(val `$ref`: String, override val default: Any? = null) : OpenApiSpecComponentSchema(default) data class ReferencedSchema(val `$ref`: String, override val default: Any? = null) : OpenApiSpecComponentSchema(default)
data class AnyOfReferencedSchema(val anyOf: List<ReferencedSchema>) : OpenApiSpecComponentSchema()
data class ObjectSchema( data class ObjectSchema(
val properties: Map<String, OpenApiSpecComponentSchema>, val properties: Map<String, OpenApiSpecComponentSchema>,

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
// TODO I *think* the only thing I need here is the security https://swagger.io/specification/#components-object // TODO I *think* the only thing I need here is the security https://swagger.io/specification/#components-object
data class OpenApiSpecComponents( data class OpenApiSpecComponents(

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
import java.net.URI import java.net.URI

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
import java.net.URI import java.net.URI

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
import java.net.URI import java.net.URI

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
import java.net.URI import java.net.URI

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpecLink( data class OpenApiSpecLink(
val operationRef: String?, // todo mutually exclusive with operationId val operationRef: String?, // todo mutually exclusive with operationId

View File

@ -1,7 +1,7 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpecMediaType<T>( data class OpenApiSpecMediaType<T>(
val schema: OpenApiSpecReferenceObject, val schema: OpenApiSpecReferencable,
val examples: Map<String, ExampleWrapper<T>>? = null val examples: Map<String, ExampleWrapper<T>>? = null
) )

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
import java.net.URI import java.net.URI

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpecOAuthFlows( data class OpenApiSpecOAuthFlows(
val implicit: OpenApiSpecOAuthFlow?, val implicit: OpenApiSpecOAuthFlow?,

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpecPathItem( data class OpenApiSpecPathItem(
var get: OpenApiSpecPathItemOperation? = null, var get: OpenApiSpecPathItemOperation? = null,

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpecPathItemOperation( data class OpenApiSpecPathItemOperation(
var tags: Set<String> = emptySet(), var tags: Set<String> = emptySet(),

View File

@ -1,15 +1,16 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
sealed class OpenApiSpecReferencable sealed interface OpenApiSpecReferencable
class OpenApiSpecReferenceObject(val `$ref`: String) : OpenApiSpecReferencable() data class OpenApiAnyOf(val anyOf: List<OpenApiSpecReferenceObject>) : OpenApiSpecReferencable
data class OpenApiSpecReferenceObject(val `$ref`: String) : OpenApiSpecReferencable
data class OpenApiSpecResponse<T>( data class OpenApiSpecResponse<T>(
val description: String? = null, val description: String? = null,
val headers: Map<String, OpenApiSpecReferencable>? = null, val headers: Map<String, OpenApiSpecReferencable>? = null,
val content: Map<String, OpenApiSpecMediaType<T>>? = null, val content: Map<String, OpenApiSpecMediaType<T>>? = null,
val links: Map<String, OpenApiSpecReferencable>? = null val links: Map<String, OpenApiSpecReferencable>? = null
) : OpenApiSpecReferencable() ) : OpenApiSpecReferencable
data class OpenApiSpecParameter( data class OpenApiSpecParameter(
val name: String, val name: String,
@ -21,10 +22,10 @@ data class OpenApiSpecParameter(
val allowEmptyValue: Boolean? = null, val allowEmptyValue: Boolean? = null,
val style: String? = null, val style: String? = null,
val explode: Boolean? = null val explode: Boolean? = null
) : OpenApiSpecReferencable() ) : OpenApiSpecReferencable
data class OpenApiSpecRequest<T>( data class OpenApiSpecRequest<T>(
val description: String?, val description: String?,
val content: Map<String, OpenApiSpecMediaType<T>>, val content: Map<String, OpenApiSpecMediaType<T>>,
val required: Boolean = false val required: Boolean = false
) : OpenApiSpecReferencable() ) : OpenApiSpecReferencable

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpecSchemaSecurity( data class OpenApiSpecSchemaSecurity(
val type: String? = null, // TODO Enum? "apiKey", "http", "oauth2", "openIdConnect" val type: String? = null, // TODO Enum? "apiKey", "http", "oauth2", "openIdConnect"

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
import java.net.URI import java.net.URI

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpecServerVariable( data class OpenApiSpecServerVariable(
val `enum`: Set<String>, // todo enforce not empty val `enum`: Set<String>, // todo enforce not empty

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.models.oas package io.bkbn.kompendium.models.oas
data class OpenApiSpecTag( data class OpenApiSpecTag(
val name: String, val name: String,

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.path package io.bkbn.kompendium.path
import io.ktor.routing.PathSegmentConstantRouteSelector import io.ktor.routing.PathSegmentConstantRouteSelector
import io.ktor.routing.PathSegmentParameterRouteSelector import io.ktor.routing.PathSegmentParameterRouteSelector

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.path package io.bkbn.kompendium.path
import io.ktor.routing.Route import io.ktor.routing.Route

View File

@ -0,0 +1,26 @@
package io.bkbn.kompendium.routes
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import io.bkbn.kompendium.models.oas.OpenApiSpec
import io.ktor.application.call
import io.ktor.response.respondText
import io.ktor.routing.Routing
import io.ktor.routing.get
import io.ktor.routing.route
/**
* Provides an out-of-the-box route to return the generated [OpenApiSpec]
* @param oas spec that is returned
*/
fun Routing.openApi(oas: OpenApiSpec) {
val om = ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.enable(SerializationFeature.INDENT_OUTPUT)
route("/openapi.json") {
get {
call.respondText { om.writeValueAsString(oas) }
}
}
}

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.routes package io.bkbn.kompendium.routes
import io.ktor.application.call import io.ktor.application.call
import io.ktor.html.respondHtml import io.ktor.html.respondHtml
@ -13,7 +13,7 @@ import kotlinx.html.script
import kotlinx.html.style import kotlinx.html.style
import kotlinx.html.title import kotlinx.html.title
import kotlinx.html.unsafe import kotlinx.html.unsafe
import org.leafygreens.kompendium.models.oas.OpenApiSpec import io.bkbn.kompendium.models.oas.OpenApiSpec
/** /**
* Provides an out-of-the-box route to view docs using ReDoc * Provides an out-of-the-box route to view docs using ReDoc

View File

@ -1,12 +1,12 @@
package org.leafygreens.kompendium.util package io.bkbn.kompendium.util
import io.bkbn.kompendium.util.Helpers.getReferenceSlug
import java.lang.reflect.ParameterizedType import java.lang.reflect.ParameterizedType
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.full.createType import kotlin.reflect.full.createType
import kotlin.reflect.jvm.javaField import kotlin.reflect.jvm.javaField
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
object Helpers { object Helpers {
@ -17,27 +17,6 @@ object Helpers {
val UNIT_TYPE by lazy { Unit::class.createType() } val UNIT_TYPE by lazy { Unit::class.createType() }
/**
* Simple extension function that will take a [Pair] and place it (if absent) into a [MutableMap].
*
* @receiver [MutableMap]
* @param pair to add to map
*/
fun <K, V> MutableMap<K, V>.putPairIfAbsent(pair: Pair<K, V>) = putIfAbsent(pair.first, pair.second)
/**
* Simple extension function that will convert a list with two items into a [Pair]
* @receiver [List]
* @return [Pair]
* @throws [IllegalArgumentException] when the list size is not exactly two
*/
fun <T> List<T>.toPair(): Pair<T, T> {
if (this.size != 2) {
throw IllegalArgumentException("List is not of length 2!")
}
return Pair(this[0], this[1])
}
/** /**
* Higher order function that takes a map of names to objects and will log their state ahead of function invocation * Higher order function that takes a map of names to objects and will log their state ahead of function invocation
* along with the result of the function invocation * along with the result of the function invocation
@ -54,6 +33,11 @@ object Helpers {
else -> simpleName ?: error("Could not determine simple name for $this") else -> simpleName ?: error("Could not determine simple name for $this")
} }
fun KType.getSimpleSlug(): String = when {
this.arguments.isNotEmpty() -> genericNameAdapter(this, classifier as KClass<*>)
else -> (classifier as KClass<*>).simpleName ?: error("Could not determine simple name for $this")
}
fun KType.getReferenceSlug(): String = when { fun KType.getReferenceSlug(): String = when {
arguments.isNotEmpty() -> "$COMPONENT_SLUG/${genericNameAdapter(this, classifier as KClass<*>)}" arguments.isNotEmpty() -> "$COMPONENT_SLUG/${genericNameAdapter(this, classifier as KClass<*>)}"
else -> "$COMPONENT_SLUG/${(classifier as KClass<*>).simpleName}" else -> "$COMPONENT_SLUG/${(classifier as KClass<*>).simpleName}"

View File

@ -1,6 +0,0 @@
package org.leafygreens.kompendium.models.meta
import kotlin.reflect.KType
import org.leafygreens.kompendium.models.oas.OpenApiSpecResponse
typealias ErrorMap = Map<KType, Pair<Int, OpenApiSpecResponse<*>>?>

View File

@ -1,5 +0,0 @@
package org.leafygreens.kompendium.models.meta
import org.leafygreens.kompendium.models.oas.OpenApiSpecComponentSchema
typealias SchemaMap = Map<String, OpenApiSpecComponentSchema>

View File

@ -1,20 +0,0 @@
package org.leafygreens.kompendium.routes
import io.ktor.application.call
import io.ktor.response.respond
import io.ktor.routing.Routing
import io.ktor.routing.get
import io.ktor.routing.route
import org.leafygreens.kompendium.models.oas.OpenApiSpec
/**
* Provides an out-of-the-box route to return the generated [OpenApiSpec]
* @param oas spec that is returned
*/
fun Routing.openApi(oas: OpenApiSpec) {
route("/openapi.json") {
get {
call.respond(oas)
}
}
}

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium package io.bkbn.kompendium
import io.ktor.application.Application import io.ktor.application.Application
import io.ktor.http.HttpMethod import io.ktor.http.HttpMethod
@ -10,33 +10,38 @@ import java.net.URI
import kotlin.test.AfterTest import kotlin.test.AfterTest
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo import io.bkbn.kompendium.models.oas.OpenApiSpecInfo
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfoContact import io.bkbn.kompendium.models.oas.OpenApiSpecInfoContact
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfoLicense import io.bkbn.kompendium.models.oas.OpenApiSpecInfoLicense
import org.leafygreens.kompendium.models.oas.OpenApiSpecServer import io.bkbn.kompendium.models.oas.OpenApiSpecServer
import org.leafygreens.kompendium.routes.openApi import io.bkbn.kompendium.routes.openApi
import org.leafygreens.kompendium.routes.redoc import io.bkbn.kompendium.routes.redoc
import org.leafygreens.kompendium.util.TestHelpers.getFileSnapshot import io.bkbn.kompendium.util.TestHelpers.getFileSnapshot
import org.leafygreens.kompendium.util.complexType import io.bkbn.kompendium.util.complexType
import org.leafygreens.kompendium.util.configModule import io.bkbn.kompendium.util.jacksonConfigModule
import org.leafygreens.kompendium.util.emptyGet import io.bkbn.kompendium.util.emptyGet
import org.leafygreens.kompendium.util.nestedUnderRootModule import io.bkbn.kompendium.util.genericPolymorphicResponse
import org.leafygreens.kompendium.util.nonRequiredParamsGet import io.bkbn.kompendium.util.genericPolymorphicResponseMultipleImpls
import org.leafygreens.kompendium.util.notarizedDeleteModule import io.bkbn.kompendium.util.kotlinxConfigModule
import org.leafygreens.kompendium.util.notarizedGetModule import io.bkbn.kompendium.util.nestedUnderRootModule
import org.leafygreens.kompendium.util.notarizedGetWithMultipleThrowables import io.bkbn.kompendium.util.nonRequiredParamsGet
import org.leafygreens.kompendium.util.notarizedGetWithNotarizedException import io.bkbn.kompendium.util.notarizedDeleteModule
import org.leafygreens.kompendium.util.notarizedPostModule import io.bkbn.kompendium.util.notarizedGetModule
import org.leafygreens.kompendium.util.notarizedPutModule import io.bkbn.kompendium.util.notarizedGetWithMultipleThrowables
import org.leafygreens.kompendium.util.pathParsingTestModule import io.bkbn.kompendium.util.notarizedGetWithNotarizedException
import org.leafygreens.kompendium.util.primitives import io.bkbn.kompendium.util.notarizedPostModule
import org.leafygreens.kompendium.util.returnsList import io.bkbn.kompendium.util.notarizedPutModule
import org.leafygreens.kompendium.util.rootModule import io.bkbn.kompendium.util.pathParsingTestModule
import org.leafygreens.kompendium.util.statusPageModule import io.bkbn.kompendium.util.polymorphicResponse
import org.leafygreens.kompendium.util.statusPageMultiExceptions import io.bkbn.kompendium.util.primitives
import org.leafygreens.kompendium.util.trailingSlash import io.bkbn.kompendium.util.returnsList
import org.leafygreens.kompendium.util.withDefaultParameter import io.bkbn.kompendium.util.rootModule
import org.leafygreens.kompendium.util.withExamples import io.bkbn.kompendium.util.simpleGenericResponse
import io.bkbn.kompendium.util.statusPageModule
import io.bkbn.kompendium.util.statusPageMultiExceptions
import io.bkbn.kompendium.util.trailingSlash
import io.bkbn.kompendium.util.withDefaultParameter
import io.bkbn.kompendium.util.withExamples
internal class KompendiumTest { internal class KompendiumTest {
@ -53,7 +58,7 @@ internal class KompendiumTest {
@Test @Test
fun `Notarized Get records all expected information`() { fun `Notarized Get records all expected information`() {
withTestApplication({ withTestApplication({
configModule() kotlinxConfigModule()
docs() docs()
notarizedGetModule() notarizedGetModule()
}) { }) {
@ -69,7 +74,7 @@ internal class KompendiumTest {
@Test @Test
fun `Notarized Get does not interrupt the pipeline`() { fun `Notarized Get does not interrupt the pipeline`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
notarizedGetModule() notarizedGetModule()
}) { }) {
@ -85,7 +90,7 @@ internal class KompendiumTest {
@Test @Test
fun `Notarized Post records all expected information`() { fun `Notarized Post records all expected information`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
notarizedPostModule() notarizedPostModule()
}) { }) {
@ -101,7 +106,7 @@ internal class KompendiumTest {
@Test @Test
fun `Notarized post does not interrupt the pipeline`() { fun `Notarized post does not interrupt the pipeline`() {
withTestApplication({ withTestApplication({
configModule() kotlinxConfigModule()
docs() docs()
notarizedPostModule() notarizedPostModule()
}) { }) {
@ -117,7 +122,7 @@ internal class KompendiumTest {
@Test @Test
fun `Notarized Put records all expected information`() { fun `Notarized Put records all expected information`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
notarizedPutModule() notarizedPutModule()
}) { }) {
@ -134,7 +139,7 @@ internal class KompendiumTest {
@Test @Test
fun `Notarized put does not interrupt the pipeline`() { fun `Notarized put does not interrupt the pipeline`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
notarizedPutModule() notarizedPutModule()
}) { }) {
@ -150,7 +155,7 @@ internal class KompendiumTest {
@Test @Test
fun `Notarized delete records all expected information`() { fun `Notarized delete records all expected information`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
notarizedDeleteModule() notarizedDeleteModule()
}) { }) {
@ -166,7 +171,7 @@ internal class KompendiumTest {
@Test @Test
fun `Notarized delete does not interrupt the pipeline`() { fun `Notarized delete does not interrupt the pipeline`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
notarizedDeleteModule() notarizedDeleteModule()
}) { }) {
@ -181,7 +186,7 @@ internal class KompendiumTest {
@Test @Test
fun `Path parser stores the expected path`() { fun `Path parser stores the expected path`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
pathParsingTestModule() pathParsingTestModule()
}) { }) {
@ -197,7 +202,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can notarize the root route`() { fun `Can notarize the root route`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
rootModule() rootModule()
}) { }) {
@ -213,7 +218,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can call the root route`() { fun `Can call the root route`() {
withTestApplication({ withTestApplication({
configModule() kotlinxConfigModule()
docs() docs()
rootModule() rootModule()
}) { }) {
@ -229,7 +234,7 @@ internal class KompendiumTest {
@Test @Test
fun `Nested under root module does not append trailing slash`() { fun `Nested under root module does not append trailing slash`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
nestedUnderRootModule() nestedUnderRootModule()
}) { }) {
@ -245,7 +250,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can notarize a trailing slash route`() { fun `Can notarize a trailing slash route`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
trailingSlash() trailingSlash()
}) { }) {
@ -261,7 +266,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can call a trailing slash route`() { fun `Can call a trailing slash route`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
trailingSlash() trailingSlash()
}) { }) {
@ -277,7 +282,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can notarize a complex type`() { fun `Can notarize a complex type`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
complexType() complexType()
}) { }) {
@ -293,7 +298,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can notarize primitives`() { fun `Can notarize primitives`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
primitives() primitives()
}) { }) {
@ -309,7 +314,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can notarize a top level list response`() { fun `Can notarize a top level list response`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
returnsList() returnsList()
}) { }) {
@ -325,7 +330,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can notarize route with no request params and no response body`() { fun `Can notarize route with no request params and no response body`() {
withTestApplication({ withTestApplication({
configModule() kotlinxConfigModule()
docs() docs()
emptyGet() emptyGet()
}) { }) {
@ -341,7 +346,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can notarize route with non-required params`() { fun `Can notarize route with non-required params`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
nonRequiredParamsGet() nonRequiredParamsGet()
}) { }) {
@ -357,7 +362,7 @@ internal class KompendiumTest {
@Test @Test
fun `Generates the expected redoc`() { fun `Generates the expected redoc`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
returnsList() returnsList()
}) { }) {
@ -374,7 +379,7 @@ internal class KompendiumTest {
fun `Generates additional responses when passed a throwable`() { fun `Generates additional responses when passed a throwable`() {
withTestApplication({ withTestApplication({
statusPageModule() statusPageModule()
configModule() jacksonConfigModule()
docs() docs()
notarizedGetWithNotarizedException() notarizedGetWithNotarizedException()
}) { }) {
@ -391,7 +396,7 @@ internal class KompendiumTest {
fun `Generates additional responses when passed multiple throwables`() { fun `Generates additional responses when passed multiple throwables`() {
withTestApplication({ withTestApplication({
statusPageMultiExceptions() statusPageMultiExceptions()
configModule() jacksonConfigModule()
docs() docs()
notarizedGetWithMultipleThrowables() notarizedGetWithMultipleThrowables()
}) { }) {
@ -407,7 +412,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can generate example response and request bodies`() { fun `Can generate example response and request bodies`() {
withTestApplication({ withTestApplication({
configModule() kotlinxConfigModule()
docs() docs()
withExamples() withExamples()
}) { }) {
@ -423,7 +428,7 @@ internal class KompendiumTest {
@Test @Test
fun `Can generate a default parameter value`() { fun `Can generate a default parameter value`() {
withTestApplication({ withTestApplication({
configModule() jacksonConfigModule()
docs() docs()
withDefaultParameter() withDefaultParameter()
}) { }) {
@ -436,6 +441,69 @@ internal class KompendiumTest {
} }
} }
@Test
fun `Can generate a polymorphic response type`() {
withTestApplication({
jacksonConfigModule()
docs()
polymorphicResponse()
}) {
// do
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
// expect
val expected = getFileSnapshot("polymorphic_response.json").trim()
assertEquals(expected, json, "The received json spec should match the expected content")
}
}
@Test
fun `Can generate a response type with a generic type`() {
withTestApplication({
jacksonConfigModule()
docs()
simpleGenericResponse()
}) {
// do
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
// expect
val expected = getFileSnapshot("generic_response.json").trim()
assertEquals(expected, json, "The received json spec should match the expected content")
}
}
@Test
fun `Can generate a polymorphic response type with generics`() {
withTestApplication({
jacksonConfigModule()
docs()
genericPolymorphicResponse()
}) {
// do
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
// expect
val expected = getFileSnapshot("polymorphic_response_with_generics.json").trim()
assertEquals(expected, json, "The received json spec should match the expected content")
}
}
@Test
fun `Absolute Psycho Inheritance Test`() {
withTestApplication({
kotlinxConfigModule()
docs()
genericPolymorphicResponseMultipleImpls()
}) {
// do
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
// expect
val expected = getFileSnapshot("crazy_polymorphic_example.json").trim()
assertEquals(expected, json, "The received json spec should match the expected content")
}
}
private val oas = Kompendium.openApiSpec.copy( private val oas = Kompendium.openApiSpec.copy(
info = OpenApiSpecInfo( info = OpenApiSpecInfo(
@ -450,7 +518,7 @@ internal class KompendiumTest {
), ),
license = OpenApiSpecInfoLicense( license = OpenApiSpecInfoLicense(
name = "MIT", name = "MIT",
url = URI("https://github.com/lg-backbone/kompendium/blob/main/LICENSE") url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE")
) )
), ),
servers = mutableListOf( servers = mutableListOf(

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium package io.bkbn.kompendium
import java.util.UUID import java.util.UUID
import kotlin.test.Test import kotlin.test.Test
@ -7,21 +7,13 @@ import kotlin.test.assertFailsWith
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
import kotlin.test.assertTrue import kotlin.test.assertTrue
import org.leafygreens.kompendium.Kontent.generateKontent import io.bkbn.kompendium.Kontent.generateKontent
import org.leafygreens.kompendium.Kontent.generateParameterKontent import io.bkbn.kompendium.Kontent.generateParameterKontent
import org.leafygreens.kompendium.models.oas.DictionarySchema import io.bkbn.kompendium.models.oas.DictionarySchema
import org.leafygreens.kompendium.models.oas.FormatSchema import io.bkbn.kompendium.models.oas.FormatSchema
import org.leafygreens.kompendium.models.oas.ObjectSchema import io.bkbn.kompendium.models.oas.ObjectSchema
import org.leafygreens.kompendium.models.oas.ReferencedSchema import io.bkbn.kompendium.models.oas.ReferencedSchema
import org.leafygreens.kompendium.util.ComplexRequest import io.bkbn.kompendium.util.*
import org.leafygreens.kompendium.util.TestInvalidMap
import org.leafygreens.kompendium.util.TestNestedModel
import org.leafygreens.kompendium.util.TestSimpleModel
import org.leafygreens.kompendium.util.TestSimpleWithEnumList
import org.leafygreens.kompendium.util.TestSimpleWithEnums
import org.leafygreens.kompendium.util.TestSimpleWithList
import org.leafygreens.kompendium.util.TestSimpleWithMap
import org.leafygreens.kompendium.util.TestWithUUID
@ExperimentalStdlibApi @ExperimentalStdlibApi
internal class KontentTest { internal class KontentTest {
@ -45,6 +37,18 @@ internal class KontentTest {
assertEquals(FormatSchema("int64", "integer"), result["Long"]) assertEquals(FormatSchema("int64", "integer"), result["Long"])
} }
@Test
fun `Object with BigDecimal and BigInteger types`() {
// do
val result = generateKontent<TestBigNumberModel>()
// expect
assertEquals(3, result.count())
assertTrue { result.containsKey(TestBigNumberModel::class.simpleName) }
assertEquals(FormatSchema("double", "number"), result["BigDecimal"])
assertEquals(FormatSchema("int64", "integer"), result["BigInteger"])
}
@Test @Test
fun `Objects reference their base types in the cache`() { fun `Objects reference their base types in the cache`() {
// do // do

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.util package io.bkbn.kompendium.util
import java.io.File import java.io.File

View File

@ -1,15 +1,16 @@
package org.leafygreens.kompendium.util package io.bkbn.kompendium.util
import java.util.UUID import java.util.UUID
import kotlin.reflect.KParameter import io.bkbn.kompendium.annotations.KompendiumField
import kotlin.reflect.full.primaryConstructor import io.bkbn.kompendium.annotations.KompendiumParam
import org.leafygreens.kompendium.MethodParser import io.bkbn.kompendium.annotations.ParamType
import org.leafygreens.kompendium.annotations.KompendiumField import java.math.BigDecimal
import org.leafygreens.kompendium.annotations.KompendiumParam import java.math.BigInteger
import org.leafygreens.kompendium.annotations.ParamType
data class TestSimpleModel(val a: String, val b: Int) data class TestSimpleModel(val a: String, val b: Int)
data class TestBigNumberModel(val a: BigDecimal, val b: BigInteger)
data class TestNestedModel(val inner: TestSimpleModel) data class TestNestedModel(val inner: TestSimpleModel)
data class TestSimpleWithEnums(val a: String, val b: SimpleEnum) data class TestSimpleWithEnums(val a: String, val b: SimpleEnum)
@ -40,6 +41,8 @@ data class TestRequest(
data class TestResponse(val c: String) data class TestResponse(val c: String)
data class TestGeneric<T>(val messy: String, val potato: T)
data class TestCreatedResponse(val id: Int, val c: String) data class TestCreatedResponse(val id: Int, val c: String)
data class ComplexRequest( data class ComplexRequest(
@ -75,3 +78,13 @@ data class OptionalParams(
@KompendiumParam(ParamType.QUERY) val required: String, @KompendiumParam(ParamType.QUERY) val required: String,
@KompendiumParam(ParamType.QUERY) val notRequired: String? @KompendiumParam(ParamType.QUERY) val notRequired: String?
) )
sealed class FlibbityGibbit
data class SimpleGibbit(val a: String) : FlibbityGibbit()
data class ComplexGibbit(val b: String, val c: Int) : FlibbityGibbit()
sealed interface Flibbity<T>
data class Gibbity<T>(val a: T): Flibbity<T>
data class Bibbity<T>(val b: String, val f: T) : Flibbity<T>

View File

@ -1,7 +1,15 @@
package org.leafygreens.kompendium.util package io.bkbn.kompendium.util
import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.databind.SerializationFeature
import io.bkbn.kompendium.Notarized.notarizedDelete
import io.bkbn.kompendium.Notarized.notarizedException
import io.bkbn.kompendium.Notarized.notarizedGet
import io.bkbn.kompendium.Notarized.notarizedPost
import io.bkbn.kompendium.Notarized.notarizedPut
import io.bkbn.kompendium.models.meta.MethodInfo
import io.bkbn.kompendium.models.meta.RequestInfo
import io.bkbn.kompendium.models.meta.ResponseInfo
import io.ktor.application.Application import io.ktor.application.Application
import io.ktor.application.call import io.ktor.application.call
import io.ktor.application.install import io.ktor.application.install
@ -13,16 +21,9 @@ import io.ktor.response.respond
import io.ktor.response.respondText import io.ktor.response.respondText
import io.ktor.routing.route import io.ktor.routing.route
import io.ktor.routing.routing import io.ktor.routing.routing
import org.leafygreens.kompendium.Notarized.notarizedDelete import io.ktor.serialization.json
import org.leafygreens.kompendium.Notarized.notarizedException
import org.leafygreens.kompendium.Notarized.notarizedGet
import org.leafygreens.kompendium.Notarized.notarizedPost
import org.leafygreens.kompendium.Notarized.notarizedPut
import org.leafygreens.kompendium.models.meta.MethodInfo
import org.leafygreens.kompendium.models.meta.RequestInfo
import org.leafygreens.kompendium.models.meta.ResponseInfo
fun Application.configModule() { fun Application.jacksonConfigModule() {
install(ContentNegotiation) { install(ContentNegotiation) {
jackson { jackson {
enable(SerializationFeature.INDENT_OUTPUT) enable(SerializationFeature.INDENT_OUTPUT)
@ -31,9 +32,20 @@ fun Application.configModule() {
} }
} }
fun Application.kotlinxConfigModule() {
install(ContentNegotiation) {
json()
}
}
fun Application.statusPageModule() { fun Application.statusPageModule() {
install(StatusPages) { install(StatusPages) {
notarizedException<Exception, ExceptionResponse>(info = ResponseInfo(HttpStatusCode.BadRequest, "Bad Things Happened")) { notarizedException<Exception, ExceptionResponse>(
info = ResponseInfo(
HttpStatusCode.BadRequest,
"Bad Things Happened"
)
) {
call.respond(HttpStatusCode.BadRequest, ExceptionResponse("Why you do dis?")) call.respond(HttpStatusCode.BadRequest, ExceptionResponse("Why you do dis?"))
} }
} }
@ -41,10 +53,17 @@ fun Application.statusPageModule() {
fun Application.statusPageMultiExceptions() { fun Application.statusPageMultiExceptions() {
install(StatusPages) { install(StatusPages) {
notarizedException<AccessDeniedException, Unit>(info = ResponseInfo(HttpStatusCode.Forbidden, "New API who dis?")) { notarizedException<AccessDeniedException, Unit>(
info = ResponseInfo(HttpStatusCode.Forbidden, "New API who dis?")
) {
call.respond(HttpStatusCode.Forbidden) call.respond(HttpStatusCode.Forbidden)
} }
notarizedException<Exception, ExceptionResponse>(info = ResponseInfo(HttpStatusCode.BadRequest, "Bad Things Happened")) { notarizedException<Exception, ExceptionResponse>(
info = ResponseInfo(
HttpStatusCode.BadRequest,
"Bad Things Happened"
)
) {
call.respond(HttpStatusCode.BadRequest, ExceptionResponse("Why you do dis?")) call.respond(HttpStatusCode.BadRequest, ExceptionResponse("Why you do dis?"))
} }
} }
@ -255,3 +274,48 @@ fun Application.nonRequiredParamsGet() {
} }
} }
} }
fun Application.polymorphicResponse() {
routing {
route("/test/polymorphic") {
notarizedGet(TestResponseInfo.polymorphicResponse) {
call.respond(HttpStatusCode.OK, SimpleGibbit("hey"))
}
}
}
}
fun Application.genericPolymorphicResponse() {
routing {
route("/test/polymorphic") {
notarizedGet(TestResponseInfo.genericPolymorphicResponse) {
call.respond(HttpStatusCode.OK, Gibbity("hey"))
}
}
}
}
fun Application.genericPolymorphicResponseMultipleImpls() {
routing {
route("/test/polymorphic") {
notarizedGet(TestResponseInfo.genericPolymorphicResponse) {
call.respond(HttpStatusCode.OK, Gibbity("hey"))
}
}
route("/test/also/poly") {
notarizedGet(TestResponseInfo.anotherGenericPolymorphicResponse) {
call.respond(HttpStatusCode.OK, Bibbity("test", ComplexGibbit("nice", 1)))
}
}
}
}
fun Application.simpleGenericResponse() {
routing {
route("/test/polymorphic") {
notarizedGet(TestResponseInfo.genericResponse) {
call.respond(HttpStatusCode.OK, Gibbity("hey"))
}
}
}
}

View File

@ -1,9 +1,12 @@
package org.leafygreens.kompendium.util package io.bkbn.kompendium.util
import io.bkbn.kompendium.models.meta.MethodInfo.DeleteInfo
import io.bkbn.kompendium.models.meta.MethodInfo.GetInfo
import io.bkbn.kompendium.models.meta.MethodInfo.PostInfo
import io.bkbn.kompendium.models.meta.MethodInfo.PutInfo
import io.bkbn.kompendium.models.meta.RequestInfo
import io.bkbn.kompendium.models.meta.ResponseInfo
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import org.leafygreens.kompendium.models.meta.MethodInfo
import org.leafygreens.kompendium.models.meta.RequestInfo
import org.leafygreens.kompendium.models.meta.ResponseInfo
object TestResponseInfo { object TestResponseInfo {
private val testGetResponse = ResponseInfo<TestResponse>(HttpStatusCode.OK, "A Successful Endeavor") private val testGetResponse = ResponseInfo<TestResponse>(HttpStatusCode.OK, "A Successful Endeavor")
@ -16,12 +19,12 @@ object TestResponseInfo {
private val testRequest = RequestInfo<TestRequest>("A Test request") private val testRequest = RequestInfo<TestRequest>("A Test request")
private val testRequestAgain = RequestInfo<Int>("A Test request") private val testRequestAgain = RequestInfo<Int>("A Test request")
private val complexRequest = RequestInfo<ComplexRequest>("A Complex request") private val complexRequest = RequestInfo<ComplexRequest>("A Complex request")
val testGetInfo = MethodInfo.GetInfo<TestParams, TestResponse>( val testGetInfo = GetInfo<TestParams, TestResponse>(
summary = "Another get test", summary = "Another get test",
description = "testing more", description = "testing more",
responseInfo = testGetResponse responseInfo = testGetResponse
) )
val testGetInfoAgain = MethodInfo.GetInfo<TestParams, List<TestResponse>>( val testGetInfoAgain = GetInfo<TestParams, List<TestResponse>>(
summary = "Another get test", summary = "Another get test",
description = "testing more", description = "testing more",
responseInfo = testGetListResponse responseInfo = testGetListResponse
@ -32,40 +35,64 @@ object TestResponseInfo {
val testGetWithMultipleExceptions = testGetInfo.copy( val testGetWithMultipleExceptions = testGetInfo.copy(
canThrow = setOf(AccessDeniedException::class, Exception::class) canThrow = setOf(AccessDeniedException::class, Exception::class)
) )
val testPostInfo = MethodInfo.PostInfo<TestParams, TestRequest, TestCreatedResponse>( val testPostInfo = PostInfo<TestParams, TestRequest, TestCreatedResponse>(
summary = "Test post endpoint", summary = "Test post endpoint",
description = "Post your tests here!", description = "Post your tests here!",
responseInfo = testPostResponse, responseInfo = testPostResponse,
requestInfo = testRequest requestInfo = testRequest
) )
val testPutInfo = MethodInfo.PutInfo<Unit, ComplexRequest, TestCreatedResponse>( val testPutInfo = PutInfo<Unit, ComplexRequest, TestCreatedResponse>(
summary = "Test put endpoint", summary = "Test put endpoint",
description = "Put your tests here!", description = "Put your tests here!",
responseInfo = testPostResponse, responseInfo = testPostResponse,
requestInfo = complexRequest requestInfo = complexRequest
) )
val testPutInfoAlso = MethodInfo.PutInfo<TestParams, TestRequest, TestCreatedResponse>( val testPutInfoAlso = PutInfo<TestParams, TestRequest, TestCreatedResponse>(
summary = "Test put endpoint", summary = "Test put endpoint",
description = "Put your tests here!", description = "Put your tests here!",
responseInfo = testPostResponse, responseInfo = testPostResponse,
requestInfo = testRequest requestInfo = testRequest
) )
val testPutInfoAgain = MethodInfo.PutInfo<Unit, Int, Boolean>( val testPutInfoAgain = PutInfo<Unit, Int, Boolean>(
summary = "Test put endpoint", summary = "Test put endpoint",
description = "Put your tests here!", description = "Put your tests here!",
responseInfo = testPostResponseAgain, responseInfo = testPostResponseAgain,
requestInfo = testRequestAgain requestInfo = testRequestAgain
) )
val testDeleteInfo = MethodInfo.DeleteInfo<TestParams, Unit>( val testDeleteInfo = DeleteInfo<TestParams, Unit>(
summary = "Test delete endpoint", summary = "Test delete endpoint",
description = "testing my deletes", description = "testing my deletes",
responseInfo = testDeleteResponse responseInfo = testDeleteResponse
) )
val emptyTestGetInfo = val emptyTestGetInfo =
MethodInfo.GetInfo<OptionalParams, Unit>( GetInfo<OptionalParams, Unit>(
summary = "No request params and response body", summary = "No request params and response body",
description = "testing more" description = "testing more"
) )
val trulyEmptyTestGetInfo = val trulyEmptyTestGetInfo = GetInfo<Unit, Unit>(
MethodInfo.GetInfo<Unit, Unit>(summary = "No request params and response body", description = "testing more") summary = "No request params and response body",
description = "testing more"
)
val polymorphicResponse = GetInfo<Unit, FlibbityGibbit>(
summary = "All the gibbits",
description = "Polymorphic response",
responseInfo = simpleOkResponse()
)
val genericPolymorphicResponse = GetInfo<Unit, Flibbity<TestNested>>(
summary = "More flibbity",
description = "Polymorphic with generics",
responseInfo = simpleOkResponse()
)
val anotherGenericPolymorphicResponse = GetInfo<Unit, Flibbity<FlibbityGibbit>>(
summary = "The Most Flibbity",
description = "Polymorphic with generics but like... crazier",
responseInfo = simpleOkResponse()
)
val genericResponse = GetInfo<Unit, TestGeneric<Int>>(
summary = "Single Generic",
description = "Simple generic data class",
responseInfo = simpleOkResponse()
)
private fun <T> simpleOkResponse() = ResponseInfo<T>(HttpStatusCode.OK, "A successful endeavor")
} }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -61,40 +61,26 @@
"String" : { "String" : {
"type" : "string" "type" : "string"
}, },
"Int" : {
"format" : "int32",
"type" : "integer"
},
"TestCreatedResponse" : {
"properties" : {
"c" : {
"$ref" : "#/components/schemas/String"
},
"id" : {
"$ref" : "#/components/schemas/Int"
}
},
"type" : "object"
},
"SimpleEnum" : { "SimpleEnum" : {
"enum" : [ "ONE", "TWO" ], "type" : "string",
"type" : "string" "enum" : [ "ONE", "TWO" ]
}, },
"CrazyItem" : { "CrazyItem" : {
"type" : "object",
"properties" : { "properties" : {
"enumeration" : { "enumeration" : {
"$ref" : "#/components/schemas/SimpleEnum" "$ref" : "#/components/schemas/SimpleEnum"
} }
}, }
"type" : "object"
}, },
"Map-String-CrazyItem" : { "Map-String-CrazyItem" : {
"type" : "object",
"additionalProperties" : { "additionalProperties" : {
"$ref" : "#/components/schemas/CrazyItem" "$ref" : "#/components/schemas/CrazyItem"
}, }
"type" : "object"
}, },
"NestedComplexItem" : { "NestedComplexItem" : {
"type" : "object",
"properties" : { "properties" : {
"alias" : { "alias" : {
"$ref" : "#/components/schemas/Map-String-CrazyItem" "$ref" : "#/components/schemas/Map-String-CrazyItem"
@ -102,16 +88,16 @@
"name" : { "name" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"List-NestedComplexItem" : { "List-NestedComplexItem" : {
"type" : "array",
"items" : { "items" : {
"$ref" : "#/components/schemas/NestedComplexItem" "$ref" : "#/components/schemas/NestedComplexItem"
}, }
"type" : "array"
}, },
"ComplexRequest" : { "ComplexRequest" : {
"type" : "object",
"properties" : { "properties" : {
"amazingField" : { "amazingField" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
@ -122,8 +108,22 @@
"tables" : { "tables" : {
"$ref" : "#/components/schemas/List-NestedComplexItem" "$ref" : "#/components/schemas/List-NestedComplexItem"
} }
}
}, },
"type" : "object" "Int" : {
"type" : "integer",
"format" : "int32"
},
"TestCreatedResponse" : {
"type" : "object",
"properties" : {
"c" : {
"$ref" : "#/components/schemas/String"
},
"id" : {
"$ref" : "#/components/schemas/Int"
}
}
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -0,0 +1,164 @@
{
"openapi" : "3.0.3",
"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" : {
"/test/polymorphic" : {
"get" : {
"tags" : [ ],
"summary" : "More flibbity",
"description" : "Polymorphic with generics",
"parameters" : [ ],
"responses" : {
"200" : {
"description" : "A successful endeavor",
"content" : {
"application/json" : {
"schema" : {
"anyOf" : [ {
"$ref" : "#/components/schemas/Gibbity-TestNested"
}, {
"$ref" : "#/components/schemas/Bibbity-TestNested"
} ]
}
}
}
}
},
"deprecated" : false
}
},
"/test/also/poly" : {
"get" : {
"tags" : [ ],
"summary" : "The Most Flibbity",
"description" : "Polymorphic with generics but like... crazier",
"parameters" : [ ],
"responses" : {
"200" : {
"description" : "A successful endeavor",
"content" : {
"application/json" : {
"schema" : {
"anyOf" : [ {
"$ref" : "#/components/schemas/Gibbity-FlibbityGibbit"
}, {
"$ref" : "#/components/schemas/Bibbity-FlibbityGibbit"
} ]
}
}
}
}
},
"deprecated" : false
}
}
},
"components" : {
"schemas" : {
"String" : {
"type" : "string"
},
"TestNested" : {
"type" : "object",
"properties" : {
"nesty" : {
"$ref" : "#/components/schemas/String"
}
}
},
"Gibbity-TestNested" : {
"type" : "object",
"properties" : {
"a" : {
"$ref" : "#/components/schemas/TestNested"
}
}
},
"Bibbity-TestNested" : {
"type" : "object",
"properties" : {
"b" : {
"$ref" : "#/components/schemas/String"
},
"f" : {
"$ref" : "#/components/schemas/TestNested"
}
}
},
"SimpleGibbit" : {
"type" : "object",
"properties" : {
"a" : {
"$ref" : "#/components/schemas/String"
}
}
},
"Int" : {
"type" : "integer",
"format" : "int32"
},
"ComplexGibbit" : {
"type" : "object",
"properties" : {
"b" : {
"$ref" : "#/components/schemas/String"
},
"c" : {
"$ref" : "#/components/schemas/Int"
}
}
},
"Gibbity-FlibbityGibbit" : {
"type" : "object",
"properties" : {
"a" : {
"anyOf" : [ {
"$ref" : "#/components/schemas/SimpleGibbit"
}, {
"$ref" : "#/components/schemas/ComplexGibbit"
} ]
}
}
},
"Bibbity-FlibbityGibbit" : {
"type" : "object",
"properties" : {
"b" : {
"$ref" : "#/components/schemas/String"
},
"f" : {
"anyOf" : [ {
"$ref" : "#/components/schemas/SimpleGibbit"
}, {
"$ref" : "#/components/schemas/ComplexGibbit"
} ]
}
}
}
},
"securitySchemes" : { }
},
"security" : [ ],
"tags" : [ ]
}

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -85,40 +85,33 @@
}, },
"components" : { "components" : {
"schemas" : { "schemas" : {
"Long" : {
"type" : "integer",
"format" : "int64"
},
"List-Long" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/Long"
}
},
"Double" : {
"type" : "number",
"format" : "double"
},
"String" : { "String" : {
"type" : "string" "type" : "string"
}, },
"TestResponse" : {
"properties" : {
"c" : {
"$ref" : "#/components/schemas/String"
}
},
"type" : "object"
},
"Long" : {
"format" : "int64",
"type" : "integer"
},
"List-Long" : {
"items" : {
"$ref" : "#/components/schemas/Long"
},
"type" : "array"
},
"Double" : {
"format" : "double",
"type" : "number"
},
"TestNested" : { "TestNested" : {
"type" : "object",
"properties" : { "properties" : {
"nesty" : { "nesty" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"TestRequest" : { "TestRequest" : {
"type" : "object",
"properties" : { "properties" : {
"aaa" : { "aaa" : {
"$ref" : "#/components/schemas/List-Long" "$ref" : "#/components/schemas/List-Long"
@ -129,8 +122,15 @@
"fieldName" : { "fieldName" : {
"$ref" : "#/components/schemas/TestNested" "$ref" : "#/components/schemas/TestNested"
} }
}
}, },
"type" : "object" "TestResponse" : {
"type" : "object",
"properties" : {
"c" : {
"$ref" : "#/components/schemas/String"
}
}
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -0,0 +1,73 @@
{
"openapi" : "3.0.3",
"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" : {
"/test/polymorphic" : {
"get" : {
"tags" : [ ],
"summary" : "Single Generic",
"description" : "Simple generic data class",
"parameters" : [ ],
"responses" : {
"200" : {
"description" : "A successful endeavor",
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/TestGeneric-Int"
}
}
}
}
},
"deprecated" : false
}
}
},
"components" : {
"schemas" : {
"String" : {
"type" : "string"
},
"Int" : {
"type" : "integer",
"format" : "int32"
},
"TestGeneric-Int" : {
"type" : "object",
"properties" : {
"messy" : {
"$ref" : "#/components/schemas/String"
},
"potato" : {
"$ref" : "#/components/schemas/Int"
}
}
}
},
"securitySchemes" : { }
},
"security" : [ ],
"tags" : [ ]
}

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -68,16 +68,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -61,8 +61,8 @@
"type" : "string" "type" : "string"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -68,16 +68,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -78,24 +78,24 @@
"type" : "string" "type" : "string"
}, },
"ExceptionResponse" : { "ExceptionResponse" : {
"type" : "object",
"properties" : { "properties" : {
"message" : { "message" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -81,24 +81,24 @@
"type" : "string" "type" : "string"
}, },
"ExceptionResponse" : { "ExceptionResponse" : {
"type" : "object",
"properties" : { "properties" : {
"message" : { "message" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -75,47 +75,33 @@
}, },
"components" : { "components" : {
"schemas" : { "schemas" : {
"Long" : {
"type" : "integer",
"format" : "int64"
},
"List-Long" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/Long"
}
},
"Double" : {
"type" : "number",
"format" : "double"
},
"String" : { "String" : {
"type" : "string" "type" : "string"
}, },
"Int" : {
"format" : "int32",
"type" : "integer"
},
"TestCreatedResponse" : {
"properties" : {
"c" : {
"$ref" : "#/components/schemas/String"
},
"id" : {
"$ref" : "#/components/schemas/Int"
}
},
"type" : "object"
},
"Long" : {
"format" : "int64",
"type" : "integer"
},
"List-Long" : {
"items" : {
"$ref" : "#/components/schemas/Long"
},
"type" : "array"
},
"Double" : {
"format" : "double",
"type" : "number"
},
"TestNested" : { "TestNested" : {
"type" : "object",
"properties" : { "properties" : {
"nesty" : { "nesty" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"TestRequest" : { "TestRequest" : {
"type" : "object",
"properties" : { "properties" : {
"aaa" : { "aaa" : {
"$ref" : "#/components/schemas/List-Long" "$ref" : "#/components/schemas/List-Long"
@ -126,8 +112,22 @@
"fieldName" : { "fieldName" : {
"$ref" : "#/components/schemas/TestNested" "$ref" : "#/components/schemas/TestNested"
} }
}
}, },
"type" : "object" "Int" : {
"type" : "integer",
"format" : "int32"
},
"TestCreatedResponse" : {
"type" : "object",
"properties" : {
"c" : {
"$ref" : "#/components/schemas/String"
},
"id" : {
"$ref" : "#/components/schemas/Int"
}
}
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -58,12 +58,12 @@
}, },
"components" : { "components" : {
"schemas" : { "schemas" : {
"Int" : {
"type" : "integer",
"format" : "int32"
},
"Boolean" : { "Boolean" : {
"type" : "boolean" "type" : "boolean"
},
"Int" : {
"format" : "int32",
"type" : "integer"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -75,47 +75,33 @@
}, },
"components" : { "components" : {
"schemas" : { "schemas" : {
"Long" : {
"type" : "integer",
"format" : "int64"
},
"List-Long" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/Long"
}
},
"Double" : {
"type" : "number",
"format" : "double"
},
"String" : { "String" : {
"type" : "string" "type" : "string"
}, },
"Int" : {
"format" : "int32",
"type" : "integer"
},
"TestCreatedResponse" : {
"properties" : {
"c" : {
"$ref" : "#/components/schemas/String"
},
"id" : {
"$ref" : "#/components/schemas/Int"
}
},
"type" : "object"
},
"Long" : {
"format" : "int64",
"type" : "integer"
},
"List-Long" : {
"items" : {
"$ref" : "#/components/schemas/Long"
},
"type" : "array"
},
"Double" : {
"format" : "double",
"type" : "number"
},
"TestNested" : { "TestNested" : {
"type" : "object",
"properties" : { "properties" : {
"nesty" : { "nesty" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"TestRequest" : { "TestRequest" : {
"type" : "object",
"properties" : { "properties" : {
"aaa" : { "aaa" : {
"$ref" : "#/components/schemas/List-Long" "$ref" : "#/components/schemas/List-Long"
@ -126,8 +112,22 @@
"fieldName" : { "fieldName" : {
"$ref" : "#/components/schemas/TestNested" "$ref" : "#/components/schemas/TestNested"
} }
}
}, },
"type" : "object" "Int" : {
"type" : "integer",
"format" : "int32"
},
"TestCreatedResponse" : {
"type" : "object",
"properties" : {
"c" : {
"$ref" : "#/components/schemas/String"
},
"id" : {
"$ref" : "#/components/schemas/Int"
}
}
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -68,16 +68,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -0,0 +1,85 @@
{
"openapi" : "3.0.3",
"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" : {
"/test/polymorphic" : {
"get" : {
"tags" : [ ],
"summary" : "All the gibbits",
"description" : "Polymorphic response",
"parameters" : [ ],
"responses" : {
"200" : {
"description" : "A successful endeavor",
"content" : {
"application/json" : {
"schema" : {
"anyOf" : [ {
"$ref" : "#/components/schemas/SimpleGibbit"
}, {
"$ref" : "#/components/schemas/ComplexGibbit"
} ]
}
}
}
}
},
"deprecated" : false
}
}
},
"components" : {
"schemas" : {
"String" : {
"type" : "string"
},
"SimpleGibbit" : {
"type" : "object",
"properties" : {
"a" : {
"$ref" : "#/components/schemas/String"
}
}
},
"Int" : {
"type" : "integer",
"format" : "int32"
},
"ComplexGibbit" : {
"type" : "object",
"properties" : {
"b" : {
"$ref" : "#/components/schemas/String"
},
"c" : {
"$ref" : "#/components/schemas/Int"
}
}
}
},
"securitySchemes" : { }
},
"security" : [ ],
"tags" : [ ]
}

View File

@ -0,0 +1,89 @@
{
"openapi" : "3.0.3",
"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" : {
"/test/polymorphic" : {
"get" : {
"tags" : [ ],
"summary" : "More flibbity",
"description" : "Polymorphic with generics",
"parameters" : [ ],
"responses" : {
"200" : {
"description" : "A successful endeavor",
"content" : {
"application/json" : {
"schema" : {
"anyOf" : [ {
"$ref" : "#/components/schemas/Gibbity-TestNested"
}, {
"$ref" : "#/components/schemas/Bibbity-TestNested"
} ]
}
}
}
}
},
"deprecated" : false
}
}
},
"components" : {
"schemas" : {
"String" : {
"type" : "string"
},
"TestNested" : {
"type" : "object",
"properties" : {
"nesty" : {
"$ref" : "#/components/schemas/String"
}
}
},
"Gibbity-TestNested" : {
"type" : "object",
"properties" : {
"a" : {
"$ref" : "#/components/schemas/TestNested"
}
}
},
"Bibbity-TestNested" : {
"type" : "object",
"properties" : {
"b" : {
"$ref" : "#/components/schemas/String"
},
"f" : {
"$ref" : "#/components/schemas/TestNested"
}
}
}
},
"securitySchemes" : { }
},
"security" : [ ],
"tags" : [ ]
}

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -32,9 +32,9 @@
"name" : "a", "name" : "a",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "default" : 100,
"type" : "integer", "type" : "integer",
"default" : 100 "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -65,16 +65,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"Boolean" : { "Boolean" : {
"type" : "boolean" "type" : "boolean"

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -68,22 +68,22 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"List-TestResponse" : { "List-TestResponse" : {
"type" : "array",
"items" : { "items" : {
"$ref" : "#/components/schemas/TestResponse" "$ref" : "#/components/schemas/TestResponse"
}, }
"type" : "array"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -68,16 +68,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -3,7 +3,7 @@
"info" : { "info" : {
"title" : "Test API", "title" : "Test API",
"version" : "1.33.7", "version" : "1.33.7",
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec", "description" : "An amazing, fully-ish 😉 generated API spec",
"termsOfService" : "https://example.com", "termsOfService" : "https://example.com",
"contact" : { "contact" : {
"name" : "Homer Simpson", "name" : "Homer Simpson",
@ -12,7 +12,7 @@
}, },
"license" : { "license" : {
"name" : "MIT", "name" : "MIT",
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE" "url" : "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
} }
}, },
"servers" : [ { "servers" : [ {
@ -40,8 +40,8 @@
"name" : "aa", "name" : "aa",
"in" : "query", "in" : "query",
"schema" : { "schema" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
}, },
"required" : true, "required" : true,
"deprecated" : false "deprecated" : false
@ -68,16 +68,16 @@
"type" : "string" "type" : "string"
}, },
"TestResponse" : { "TestResponse" : {
"type" : "object",
"properties" : { "properties" : {
"c" : { "c" : {
"$ref" : "#/components/schemas/String" "$ref" : "#/components/schemas/String"
} }
}, }
"type" : "object"
}, },
"Int" : { "Int" : {
"format" : "int32", "type" : "integer",
"type" : "integer" "format" : "int32"
} }
}, },
"securitySchemes" : { } "securitySchemes" : { }

View File

@ -1,4 +1,5 @@
plugins { plugins {
kotlin("plugin.serialization") version "1.5.0"
application application
} }
@ -11,6 +12,9 @@ dependencies {
implementation(projects.kompendiumSwaggerUi) implementation(projects.kompendiumSwaggerUi)
implementation(libs.bundles.ktor) implementation(libs.bundles.ktor)
implementation(libs.ktor.jackson)
implementation(libs.kotlinx.serialization.json)
implementation(libs.ktor.serialization)
implementation(libs.bundles.ktorAuth) implementation(libs.bundles.ktorAuth)
implementation(libs.bundles.logging) implementation(libs.bundles.logging)
@ -20,6 +24,6 @@ dependencies {
application { application {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
mainClassName = "org.leafygreens.kompendium.playground.MainKt" mainClassName = "io.bkbn.kompendium.playground.MainKt"
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=true") // TODO I don't think this is working 😢 applicationDefaultJvmArgs = listOf("-Dio.ktor.development=true") // TODO I don't think this is working 😢
} }

View File

@ -1,7 +1,24 @@
package org.leafygreens.kompendium.playground package io.bkbn.kompendium.playground
import com.fasterxml.jackson.annotation.JsonInclude import io.bkbn.kompendium.Notarized.notarizedDelete
import com.fasterxml.jackson.databind.SerializationFeature import io.bkbn.kompendium.Notarized.notarizedException
import io.bkbn.kompendium.Notarized.notarizedGet
import io.bkbn.kompendium.Notarized.notarizedPost
import io.bkbn.kompendium.Notarized.notarizedPut
import io.bkbn.kompendium.auth.KompendiumAuth.notarizedBasic
import io.bkbn.kompendium.models.meta.ResponseInfo
import io.bkbn.kompendium.playground.PlaygroundToC.testAuthenticatedSingleGetInfo
import io.bkbn.kompendium.playground.PlaygroundToC.testGetWithExamples
import io.bkbn.kompendium.playground.PlaygroundToC.testIdGetInfo
import io.bkbn.kompendium.playground.PlaygroundToC.testPostWithExamples
import io.bkbn.kompendium.playground.PlaygroundToC.testSingleDeleteInfo
import io.bkbn.kompendium.playground.PlaygroundToC.testSingleGetInfo
import io.bkbn.kompendium.playground.PlaygroundToC.testSingleGetInfoWithThrowable
import io.bkbn.kompendium.playground.PlaygroundToC.testSinglePostInfo
import io.bkbn.kompendium.playground.PlaygroundToC.testSinglePutInfo
import io.bkbn.kompendium.routes.openApi
import io.bkbn.kompendium.routes.redoc
import io.bkbn.kompendium.swagger.swaggerUI
import io.ktor.application.Application import io.ktor.application.Application
import io.ktor.application.call import io.ktor.application.call
import io.ktor.application.install import io.ktor.application.install
@ -11,33 +28,14 @@ import io.ktor.auth.authenticate
import io.ktor.features.ContentNegotiation import io.ktor.features.ContentNegotiation
import io.ktor.features.StatusPages import io.ktor.features.StatusPages
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.jackson.jackson
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondText import io.ktor.response.respondText
import io.ktor.routing.route import io.ktor.routing.route
import io.ktor.routing.routing import io.ktor.routing.routing
import io.ktor.serialization.json
import io.ktor.server.engine.embeddedServer import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty import io.ktor.server.netty.Netty
import io.ktor.webjars.Webjars import io.ktor.webjars.Webjars
import org.leafygreens.kompendium.Notarized.notarizedDelete
import org.leafygreens.kompendium.Notarized.notarizedException
import org.leafygreens.kompendium.Notarized.notarizedGet
import org.leafygreens.kompendium.Notarized.notarizedPost
import org.leafygreens.kompendium.Notarized.notarizedPut
import org.leafygreens.kompendium.auth.KompendiumAuth.notarizedBasic
import org.leafygreens.kompendium.models.meta.ResponseInfo
import org.leafygreens.kompendium.playground.PlaygroundToC.testAuthenticatedSingleGetInfo
import org.leafygreens.kompendium.playground.PlaygroundToC.testGetWithExamples
import org.leafygreens.kompendium.playground.PlaygroundToC.testIdGetInfo
import org.leafygreens.kompendium.playground.PlaygroundToC.testPostWithExamples
import org.leafygreens.kompendium.playground.PlaygroundToC.testSingleDeleteInfo
import org.leafygreens.kompendium.playground.PlaygroundToC.testSingleGetInfo
import org.leafygreens.kompendium.playground.PlaygroundToC.testSingleGetInfoWithThrowable
import org.leafygreens.kompendium.playground.PlaygroundToC.testSinglePostInfo
import org.leafygreens.kompendium.playground.PlaygroundToC.testSinglePutInfo
import org.leafygreens.kompendium.routes.openApi
import org.leafygreens.kompendium.routes.redoc
import org.leafygreens.kompendium.swagger.swaggerUI
fun main() { fun main() {
embeddedServer( embeddedServer(
@ -52,10 +50,7 @@ var featuresInstalled = false
fun Application.configModule() { fun Application.configModule() {
if (!featuresInstalled) { if (!featuresInstalled) {
install(ContentNegotiation) { install(ContentNegotiation) {
jackson { json()
enable(SerializationFeature.INDENT_OUTPUT)
setSerializationInclusion(JsonInclude.Include.NON_NULL)
}
} }
install(Authentication) { install(Authentication) {
notarizedBasic("basic") { notarizedBasic("basic") {

View File

@ -1,8 +1,8 @@
package org.leafygreens.kompendium.playground package io.bkbn.kompendium.playground
import org.leafygreens.kompendium.annotations.KompendiumField import io.bkbn.kompendium.annotations.KompendiumField
import org.leafygreens.kompendium.annotations.KompendiumParam import io.bkbn.kompendium.annotations.KompendiumParam
import org.leafygreens.kompendium.annotations.ParamType import io.bkbn.kompendium.annotations.ParamType
data class ExampleParams( data class ExampleParams(
@KompendiumParam(ParamType.PATH) val id: Int, @KompendiumParam(ParamType.PATH) val id: Int,
@ -16,6 +16,8 @@ data class JustQuery(
data class ExampleNested(val nesty: String) data class ExampleNested(val nesty: String)
data class ExampleGeneric<T>(val potato: T)
data class ExampleRequest( data class ExampleRequest(
@KompendiumField(name = "field_name") @KompendiumField(name = "field_name")
val fieldName: ExampleNested, val fieldName: ExampleNested,

View File

@ -1,9 +1,9 @@
package org.leafygreens.kompendium.playground package io.bkbn.kompendium.playground
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import org.leafygreens.kompendium.models.meta.MethodInfo import io.bkbn.kompendium.models.meta.MethodInfo
import org.leafygreens.kompendium.models.meta.RequestInfo import io.bkbn.kompendium.models.meta.RequestInfo
import org.leafygreens.kompendium.models.meta.ResponseInfo import io.bkbn.kompendium.models.meta.ResponseInfo
object PlaygroundToC { object PlaygroundToC {
val testGetWithExamples = MethodInfo.GetInfo<Unit, ExampleResponse>( val testGetWithExamples = MethodInfo.GetInfo<Unit, ExampleResponse>(
@ -37,7 +37,7 @@ object PlaygroundToC {
canThrow = setOf(Exception::class) canThrow = setOf(Exception::class)
) )
val testIdGetInfo = MethodInfo.GetInfo<ExampleParams, ExampleResponse>( val testIdGetInfo = MethodInfo.GetInfo<ExampleParams, ExampleGeneric<Int>>(
summary = "Get Test", summary = "Get Test",
description = "Test for the getting", description = "Test for the getting",
tags = setOf("test", "sample", "get"), tags = setOf("test", "sample", "get"),

View File

@ -1,11 +1,11 @@
package org.leafygreens.kompendium.playground package io.bkbn.kompendium.playground
import java.net.URI import java.net.URI
import org.leafygreens.kompendium.Kompendium import io.bkbn.kompendium.Kompendium
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo import io.bkbn.kompendium.models.oas.OpenApiSpecInfo
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfoContact import io.bkbn.kompendium.models.oas.OpenApiSpecInfoContact
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfoLicense import io.bkbn.kompendium.models.oas.OpenApiSpecInfoLicense
import org.leafygreens.kompendium.models.oas.OpenApiSpecServer import io.bkbn.kompendium.models.oas.OpenApiSpecServer
val oas = Kompendium.openApiSpec.copy( val oas = Kompendium.openApiSpec.copy(
info = OpenApiSpecInfo( info = OpenApiSpecInfo(
@ -20,7 +20,7 @@ val oas = Kompendium.openApiSpec.copy(
), ),
license = OpenApiSpecInfoLicense( license = OpenApiSpecInfoLicense(
name = "MIT", name = "MIT",
url = URI("https://github.com/lg-backbone/kompendium/blob/main/LICENSE") url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE")
) )
), ),
servers = mutableListOf( servers = mutableListOf(

View File

@ -1,6 +1,7 @@
plugins { plugins {
`java-library` `java-library`
`maven-publish` `maven-publish`
signing
} }
dependencies { dependencies {
@ -11,19 +12,20 @@ dependencies {
implementation(libs.webjars.swagger.ui) implementation(libs.webjars.swagger.ui)
testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit") testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.0") testImplementation(libs.jackson.module.kotlin)
testImplementation("io.ktor:ktor-server-test-host:1.5.3") testImplementation(libs.ktor.server.test.host)
} }
java { java {
withSourcesJar() withSourcesJar()
withJavadocJar()
} }
publishing { publishing {
repositories { repositories {
maven { maven {
name = "GithubPackages" name = "GithubPackages"
url = uri("https://maven.pkg.github.com/lg-backbone/kompendium") url = uri("https://maven.pkg.github.com/bkbnio/kompendium")
credentials { credentials {
username = System.getenv("GITHUB_ACTOR") username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN") password = System.getenv("GITHUB_TOKEN")
@ -34,6 +36,41 @@ publishing {
create<MavenPublication>("kompendium") { create<MavenPublication>("kompendium") {
from(components["kotlin"]) from(components["kotlin"])
artifact(tasks.sourcesJar) artifact(tasks.sourcesJar)
artifact(tasks.javadocJar)
groupId = project.group.toString()
artifactId = project.name.toLowerCase()
version = project.version.toString()
pom {
name.set("Kompendium")
description.set("A minimally invasive OpenAPI spec generator for Ktor")
url.set("https://github.com/bkbnio/Kompendium")
licenses {
license {
name.set("MIT License")
url.set("https://mit-license.org/")
}
}
developers {
developer {
id.set("bkbnio")
name.set("Ryan Brink")
email.set("admin@bkbn.io")
}
}
scm {
connection.set("scm:git:git://github.com/bkbnio/Kompendium.git")
developerConnection.set("scm:git:ssh://github.com/bkbnio/Kompendium.git")
url.set("https://github.com/bkbnio/Kompendium.git")
}
}
} }
} }
} }
signing {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
sign(publishing.publications)
}

View File

@ -1,4 +1,4 @@
package org.leafygreens.kompendium.swagger package io.bkbn.kompendium.swagger
import io.ktor.application.call import io.ktor.application.call
import io.ktor.response.respondRedirect import io.ktor.response.respondRedirect