Skip to content

Commit

Permalink
fix issues with config merging, add specname to postBuild
Browse files Browse the repository at this point in the history
  • Loading branch information
SMILEY4 committed Jul 26, 2024
1 parent fc2e463 commit 98570ea
Show file tree
Hide file tree
Showing 27 changed files with 103 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ private fun Application.myModule() {
specAssigner = { _, _ -> PluginConfigDsl.DEFAULT_SPEC_ID }
pathFilter = { _, url -> url.firstOrNull() != "hidden" }
ignoredRouteSelectors = emptySet()
postBuild = { api -> println("Completed api: $api") }
postBuild = { api, name -> println("Completed api '$name': $api") }
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContextImpl
import io.github.smiley4.ktorswaggerui.data.PluginConfigData
import io.github.smiley4.ktorswaggerui.data.TypeDescriptor
import io.github.smiley4.ktorswaggerui.dsl.config.PluginConfigDsl
import io.github.smiley4.ktorswaggerui.routing.ApiSpec
import io.ktor.server.application.Application
Expand Down Expand Up @@ -83,12 +82,12 @@ private fun buildOpenApiSpecs(config: PluginConfigData, routes: List<RouteMeta>)
return buildMap {
routesBySpec.forEach { (specName, routes) ->
val specConfig = config.specConfigs[specName] ?: config
this[specName] = buildOpenApiSpec(specConfig, routes)
this[specName] = buildOpenApiSpec(specName, specConfig, routes)
}
}
}

private fun buildOpenApiSpec(pluginConfig: PluginConfigData, routes: List<RouteMeta>): String {
private fun buildOpenApiSpec(specName: String, pluginConfig: PluginConfigData, routes: List<RouteMeta>): String {
return try {
val schemaContext = SchemaContextImpl(pluginConfig.schemaConfig).also {
it.addGlobal(pluginConfig.schemaConfig)
Expand All @@ -99,7 +98,7 @@ private fun buildOpenApiSpec(pluginConfig: PluginConfigData, routes: List<RouteM
it.add(routes)
}
val openApi = builder(pluginConfig, schemaContext, exampleContext).build(routes)
pluginConfig.postBuild?.invoke(openApi)
pluginConfig.postBuild?.let { it(openApi, specName) }
Json.pretty(openApi)
} catch (e: Exception) {
logger.error("Error during openapi-generation", e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@ package io.github.smiley4.ktorswaggerui.data

object DataUtils {

/**
* Merges the two boolean values.
* @return true if "value" is true, value of "base" otherwise
*/
fun mergeBoolean(base: Boolean, value: Boolean) = if (value) true else base


/**
* Merges the two values.
* @return "value" if "value" is different from the given default value, "base" otherwise
*/
fun <T> mergeDefault(base: T, value: T, default: T) = if (value != default) value else base

/**
* Merges the two values.
* @return "value" if "value" is not null, "base" otherwise
*/
fun <T> merge(base: T?, value: T?) = value ?: base

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ import io.swagger.v3.oas.models.OpenAPI
* Function executed after building the openapi-spec.
* @author <a href=mailto:[email protected]>yuefeng</a> in 2024/3/25.
*/
typealias PostBuild = (openApi: OpenAPI) -> Unit
typealias PostBuild = (openApi: OpenAPI, specId: String) -> Unit
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class ExampleConfig {
this.exampleEncoder = exampleEncoder
}

/**
* Build the data object for this config.
* @param securityConfig the data for security config that might contain additional examples
*/
fun build(securityConfig: SecurityData) = ExampleConfigData(
sharedExamples = sharedExamples,
securityExamples = securityConfig.defaultUnauthorizedResponse?.body?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ class OpenApiContact {
var email: String? = ContactData.DEFAULT.email


/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: ContactData) = ContactData(
name = merge(base.name, name),
url = merge(base.url, url),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ class OpenApiExternalDocs {
*/
var url: String = "/"


/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: ExternalDocsData) = ExternalDocsData(
url = DataUtils.mergeDefault(base.url, url, ExternalDocsData.DEFAULT.url),
description = DataUtils.merge(base.description, description)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ class OpenApiInfo {
license = OpenApiLicense().apply(block)
}


/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: InfoData): InfoData {
return InfoData(
title = mergeDefault(base.title, this.title, InfoData.DEFAULT.title),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class OpenApiLicense {
*/
var identifier: String? = LicenseData.DEFAULT.identifier

/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: LicenseData) = LicenseData(
name = DataUtils.merge(base.name, name),
url = DataUtils.merge(base.url, url),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class OpenApiSecurity {

private val securitySchemes = mutableListOf<OpenApiSecurityScheme>()

/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: SecurityData) = SecurityData(
defaultUnauthorizedResponse = merge(base.defaultUnauthorizedResponse, defaultUnauthorizedResponse?.build()),
defaultSecuritySchemeNames = buildSet {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ class OpenApiSecurityScheme(
*/
var description: String? = null


/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: SecuritySchemeData) = SecuritySchemeData(
schemeName = schemeName,
type = merge(base.type, type),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class OpenApiServer {
variables[name] = OpenApiServerVariable(name).apply(block)
}

/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: ServerData) = ServerData(
url = mergeDefault(base.url, url, ServerData.DEFAULT.url),
description = merge(base.description, description),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class OpenApiServerVariable(
*/
var description: String? = null

/**
* Build the data object for this config.
*/
fun build() = ServerVariableData(
name = name,
enum = enum.toSet(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ class OpenApiTags {
*/
var tagGenerator: TagGenerator = TagsData.DEFAULT.generator


/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: TagsData) = TagsData(
tags = buildList {
addAll(base.tags)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ class OpenIdOAuthFlow {
*/
var scopes: Map<String, String>? = null


/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: OpenIdOAuthFlowData) = OpenIdOAuthFlowData(
authorizationUrl = merge(base.authorizationUrl, authorizationUrl),
tokenUrl = merge(base.tokenUrl, tokenUrl),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ class OpenIdOAuthFlows {
authorizationCode = OpenIdOAuthFlow().apply(block)
}


/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
fun build(base: OpenIdOAuthFlowsData) = OpenIdOAuthFlowsData(
implicit = implicit?.build(base.implicit ?: OpenIdOAuthFlowData.DEFAULT) ?: base.implicit,
password = password?.build(base.password ?: OpenIdOAuthFlowData.DEFAULT) ?: base.password,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ class PluginConfigDsl {
var postBuild: PostBuild? = null


/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
internal fun build(base: PluginConfigData): PluginConfigData {
val securityConfig = security.build(base.securityConfig)
return PluginConfigData(
Expand All @@ -155,7 +159,7 @@ class PluginConfigDsl {
addAll(ignoredRouteSelectors)
},
specConfigs = mutableMapOf(),
postBuild = postBuild,
postBuild = merge(base.postBuild, postBuild),
).also {
specConfigs.forEach { (specId, config) ->
it.specConfigs[specId] = config.build(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,18 @@ class SchemaConfig {
*/
inline fun <reified T> schema(schemaId: String) = schema(schemaId, KTypeDescriptor(typeOf<T>()))

/**
* Build the data object for this config.
* @param securityConfig configuration that might contain additional schemas
*/
fun build(securityConfig: SecurityData) = SchemaConfigData(
generator = generator,
schemas = schemas,
overwrite = overwrite,
securitySchemas = securityConfig.defaultUnauthorizedResponse?.body?.let {
when (it) {
is OpenApiSimpleBodyData -> listOf(it.type)
is OpenApiMultipartBodyData -> it.parts.map { it.type }
securitySchemas = securityConfig.defaultUnauthorizedResponse?.body?.let { body ->
when (body) {
is OpenApiSimpleBodyData -> listOf(body.type)
is OpenApiMultipartBodyData -> body.parts.map { it.type }
}
} ?: emptyList()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class SwaggerUIDsl {
*/
var withCredentials: Boolean = false

/**
* Build the data object for this config.
* @param base the base config to "inherit" from. Values from the base should be copied, replaced or merged together.
*/
internal fun build(base: SwaggerUIData): SwaggerUIData {
return SwaggerUIData(
validatorUrl = merge(base.validatorUrl, this.validatorUrl),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@ sealed class OpenApiBaseBody {
this.mediaTypes = mediaTypes.toList()
}

/**
* Build the data object for this config.
*/
abstract fun build(): OpenApiBaseBodyData
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class OpenApiHeader {
*/
var explode: Boolean? = null

/**
* Build the data object for this config.
*/
fun build() = OpenApiHeaderData(
description = description,
type = type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ class OpenApiMultipartPart(
inline fun <reified T> header(name: String, noinline block: OpenApiHeader.() -> Unit = {}) =
header(name, KTypeDescriptor(typeOf<T>()), block)


/**
* Build the data object for this config.
*/
fun build() = OpenApiMultipartPartData(
name = name,
type = type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ class OpenApiRequest {
this.body = body
}

/**
* Build the data object for this config.
*/
fun build() = OpenApiRequestData(
parameters = parameters.map { it.build() },
body = body?.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ class OpenApiRequestParameter(
*/
var style: Parameter.StyleEnum? = null

/**
* Build the data object for this config.
*/
fun build() = OpenApiRequestParameterData(
name = name,
type = type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ class OpenApiResponse(val statusCode: String) {
body = OpenApiMultipartBody().apply(block)
}


/**
* Build the data object for this config.
*/
fun build() = OpenApiResponseData(
statusCode = statusCode,
description = description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ class OpenApiRoute {

private val servers = mutableListOf<OpenApiServer>()


/**
* Build the data object for this config.
*/
fun build() = OpenApiRouteData(
specId = specId,
tags = tags.toSet(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ class OpenApiSimpleBody(
*/
fun exampleRef(name: String) = example(RefExampleDescriptor(name, name))


override fun build() = OpenApiSimpleBodyData(
description = description,
required = required ?: false,
Expand Down

0 comments on commit 98570ea

Please sign in to comment.