All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.javalin.plugin.openapi.dsl.OpenApiDocumentation.kt Maven / Gradle / Ivy

The newest version!
package io.javalin.plugin.openapi.dsl

import io.javalin.http.Handler
import io.javalin.plugin.openapi.annotations.ComposedType
import io.javalin.plugin.openapi.annotations.ContentType
import io.swagger.v3.oas.models.Components
import io.swagger.v3.oas.models.Operation
import io.swagger.v3.oas.models.media.Schema
import io.swagger.v3.oas.models.parameters.Parameter
import io.swagger.v3.oas.models.parameters.RequestBody
import io.swagger.v3.oas.models.responses.ApiResponse

/**
 * [OpenApiDocumentation] contains OpenAPI documentation for a [Handler].
 *
 * This class should be modified by the available functions and passed into [io.javalin.plugin.openapi.dsl.documented] which will include it
 * in the generated documentation.
 */
class OpenApiDocumentation {
    var isIgnored: Boolean? = null
    val operationUpdaterList = mutableListOf>()
    val requestBodyList = mutableListOf>()
    val parameterUpdaterListMapping = mutableMapOf>>()
    val responseUpdaterListMapping = mutableMapOf>>()
    val componentsUpdaterList = mutableListOf>()
    val formParameterList = mutableListOf()
    val fileUploadList = mutableListOf()

    fun hasRequestBodies(): Boolean = requestBodyList.isNotEmpty()
    fun hasResponses(): Boolean = responseUpdaterListMapping.values.flatten().isNotEmpty()
    fun hasFormParameter(): Boolean = formParameterList.isNotEmpty()
    fun hasFileUploads(): Boolean = fileUploadList.isNotEmpty()

    /** Hide the endpoint in the documentation */
    @JvmOverloads
    fun ignore(isIgnored: Boolean = true) = apply { this.isIgnored = isIgnored }

    // --- OPERATION ---

    /**
     * Documents the handler using the [Operation] provided by the input [applyUpdates].
     *
     * @param applyUpdates A function that returns a Swagger [Operation].
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun operation(applyUpdates: ApplyUpdates) = apply {
        operation(createUpdater(applyUpdates))
    }

    /**
     * Documents the handler using the [Operation] provided by the input [openApiUpdater].
     *
     * @param openApiUpdater A function that returns a Swagger [Operation].
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun operation(openApiUpdater: OpenApiUpdater) = apply {
        operationUpdaterList.add(openApiUpdater)
    }

    // --- PATH PARAM ---

    /**
     * Documents that the handler can receive a path parameter.
     *
     * @param name The name of the parameter.
     * @param applyUpdates A function that allows the underlying Swagger [Parameter] to modified directly.
     * @param T The class of the parameter.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  pathParam(name: String, noinline applyUpdates: ApplyUpdates? = null): OpenApiDocumentation = apply {
        pathParam(name, T::class.java, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a path parameter.
     *
     * @param name The name of the parameter.
     * @param clazz The class of the parameter.
     * @param openApiUpdater A function that allows the underlying Swagger [Parameter] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun pathParam(name: String, clazz: Class<*>, openApiUpdater: OpenApiUpdater? = null) = apply {
        val documentedQueryParameter = DocumentedParameter("path", name, clazz)
        param(documentedQueryParameter, openApiUpdater = openApiUpdater)
    }

    // --- QUERY PARAM ---

    /**
     * Documents that the handler can receive a query parameter.
     *
     * [queryParam] can be called multiple times with different [name]s that represent different parameters, all will be added to the generated documentation.
     *
     * @param name The name of the parameter.
     * @param isRepeatable Whether the parameter is repeatable.
     * @param applyUpdates A function that allows the underlying Swagger [Parameter] to modified directly.
     * @param T The class of the parameter.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  queryParam(name: String, isRepeatable: Boolean = false, noinline applyUpdates: ApplyUpdates? = null): OpenApiDocumentation = apply {
        queryParam(name, T::class.java, isRepeatable, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a query parameter.
     *
     * [queryParam] can be called multiple times with different [name]s that represent different parameters, all will be added to the generated documentation.
     *
     * @param name The name of the parameter.
     * @param clazz The class of the parameter.
     * @param isRepeatable Whether the parameter is repeatable.
     * @param openApiUpdater A function that allows the underlying Swagger [Parameter] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun queryParam(name: String, clazz: Class<*>, isRepeatable: Boolean = false, openApiUpdater: OpenApiUpdater? = null) = apply {
        val documentedQueryParameter = DocumentedParameter("query", name, clazz)
        param(documentedQueryParameter, isRepeatable, openApiUpdater)
    }

    // --- HEADER ---

    /**
     * Documents that the handler has a header.
     *
     * [header] can be called multiple times with different [name]s that represent different headers, all will be added to the generated documentation.
     *
     * @param name The name of the header.
     * @param applyUpdates A function that allows the underlying Swagger [Parameter] to modified directly.
     * @param T The class that represents the header.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  header(name: String, noinline applyUpdates: ApplyUpdates? = null): OpenApiDocumentation = apply {
        header(name, T::class.java, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler has a header.
     *
     * [header] can be called multiple times with different [name]s that represent different headers, all will be added to the generated documentation.
     *
     * @param name The name of the header.
     * @param clazz The class that represents the header.
     * @param openApiUpdater A function that allows the underlying Swagger [Parameter] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun header(name: String, clazz: Class<*>, openApiUpdater: OpenApiUpdater? = null) = apply {
        val documentedQueryParameter = DocumentedParameter("header", name, clazz)
        param(documentedQueryParameter, openApiUpdater = openApiUpdater)
    }

    // --- COOKIE ---

    /**
     * Documents that the handler can receive a cookie.
     *
     * [cookie] can be called multiple times with different [name]s that represent different cookies, all will be added to the generated documentation.
     *
     * @param name The name of the cookie.
     * @param applyUpdates A function that allows the underlying Swagger [Parameter] to modified directly.
     * @param T The class that represents the cookie.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  cookie(name: String, noinline applyUpdates: ApplyUpdates? = null): OpenApiDocumentation = apply {
        cookie(name, T::class.java, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a cookie.
     *
     * [cookie] can be called multiple times with different [name]s that represent different cookies, all will be added to the generated documentation.
     *
     * @param name The name of the cookie.
     * @param clazz The class that represents the cookie.
     * @param openApiUpdater A function that allows the underlying Swagger [Parameter] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun cookie(name: String, clazz: Class<*>, openApiUpdater: OpenApiUpdater? = null) = apply {
        val documentedQueryParameter = DocumentedParameter("cookie", name, clazz)
        param(documentedQueryParameter, openApiUpdater = openApiUpdater)
    }

    // --- PARAM ---

    /**
     * Documents that the handler can receive a parameter detailed by the input [DocumentedParameter].
     *
     * [param] can be called multiple times with different [DocumentedParameter]s that represent different parameters, all will be added to the generated documentation.
     *
     * @param documentedParameter The [DocumentedParameter] the handler can receive.
     * @param isRepeatable Whether the parameter is repeatable.
     * @param applyUpdates A function that allows the underlying Swagger [Parameter] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun param(documentedParameter: DocumentedParameter, isRepeatable: Boolean = false, applyUpdates: ApplyUpdates? = null) = apply {
        param(documentedParameter, isRepeatable, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a parameter detailed by the input [DocumentedParameter].
     *
     * [param] can be called multiple times with different [DocumentedParameter]s that represent different parameters, all will be added to the generated documentation.
     *
     * @param documentedParameter The [DocumentedParameter] the handler can receive.
     * @param isRepeatable Whether the parameter is repeatable.
     * @param openApiUpdater A function that allows the underlying Swagger [Parameter] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun param(documentedParameter: DocumentedParameter, isRepeatable: Boolean = false, openApiUpdater: OpenApiUpdater? = null) = apply {
        val parameterUpdaterList = parameterUpdaterListMapping.getOrSetDefault(documentedParameter.name, mutableListOf())
        componentsUpdaterList.add { it.applyDocumentedParameter(documentedParameter) }
        parameterUpdaterList.add {
            if (isRepeatable)
                it.applyRepeatableDocumentedParameter(documentedParameter)
            else
                it.applyDocumentedParameter(documentedParameter)
        }
        parameterUpdaterList.addIfNotNull(openApiUpdater)
    }

    // --- FORM PARAM ---

    /**
     * Documents that the handler can receive a form parameter.
     *
     * [formParam] can be called multiple times with different [name]s that represent different form parameters, all will be added to the generated documentation.
     *
     * @param name The name of the parameter.
     * @param required Whether the parameter is required.
     * @param T The class of the parameter.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  formParam(name: String, required: Boolean = false): OpenApiDocumentation = apply {
        formParam(name, T::class.java, required)
    }

    /**
     * Documents that the handler can receive a form parameter.
     *
     * [formParam] can be called multiple times with different [name]s that represent different form parameters, all will be added to the generated documentation.
     *
     * @param name The name of the parameter.
     * @param clazz The class of the parameter.
     * @param required Whether the parameter is required.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun formParam(name: String, clazz: Class<*>, required: Boolean = false) = apply {
        formParam(DocumentedFormParameter(name, clazz, required))
    }

    /**
     * Documents that the handler can receive a form parameter detailed by the input [DocumentedFormParameter].
     *
     * [formParam] can be called multiple times with different [DocumentedFormParameter]s that represent different form parameters, all will be added to the generated documentation.
     *
     * @param formParameter The [DocumentedFormParameter] the handler can receive.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun formParam(formParameter: DocumentedFormParameter) = apply {
        formParameterList.add(formParameter)
    }

    // --- FORM PARAM BODY ---

    /**
     * Documents that the handler can receive a request body with a content type of `application/x-www-form-urlencoded` in the form of [T].
     *
     * @param applyUpdates A function that allows the underlying Swagger [RequestBody] to modified directly.
     * @param T The class that the handler can receive in its request body.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  formParamBody(noinline applyUpdates: ApplyUpdates? = null) = apply {
        formParamBody(T::class.java, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a request body with the input [contentType] in the form of [T].
     *
     * If no [contentType] is provided then a content type of `application/x-www-form-urlencoded` is used.
     *
     * @param contentType The content type of the request body.
     * @param applyUpdates A function that allows the underlying Swagger [RequestBody] to modified directly.
     * @param T The class that the handler can receive in its request body.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  formParamBody(contentType: String? = null, noinline applyUpdates: ApplyUpdates? = null) = apply {
        formParamBody(T::class.java, contentType, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a request body with a content type of `application/x-www-form-urlencoded` in the form of [clazz].
     *
     * @param clazz The class that the handler can receive in its request body.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun formParamBody(clazz: Class<*>, openApiUpdater: OpenApiUpdater? = null) = apply {
        formParamBody(clazz, null, openApiUpdater)
    }

    /**
     * Documents that the handler can receive a request body with the input [contentType] in the form of [clazz].
     *
     * If no [contentType] is provided then a content type of `application/x-www-form-urlencoded` is used.
     *
     * @param clazz The class that the handler can receive in its request body.
     * @param contentType The content type of the request body.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun formParamBody(clazz: Class<*>, contentType: String? = null, openApiUpdater: OpenApiUpdater? = null) = apply {
        body(clazz, contentType ?: ContentType.FORM_DATA_URL_ENCODED, openApiUpdater)
    }

    // --- UPLOADED FILE ---

    /**
     * Documents that the handler can receive a file with the input [name].
     *
     * [uploadedFile] can be called multiple times with different [name]s that represent different files, all will be added to the generated documentation.
     *
     * @param name The name of the uploaded files.
     * @param applyUpdates A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun uploadedFile(name: String, applyUpdates: ApplyUpdates? = null) = apply {
        uploadedFile(name, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a file with the input [name].
     *
     * [uploadedFile] can be called multiple times with different [name]s that represent different files, all will be added to the generated documentation.
     *
     * @param name The name of the uploaded files.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun uploadedFile(name: String, openApiUpdater: OpenApiUpdater? = null) = apply {
        fileUploadList.add(DocumentedFileUpload(name))
        requestBodyList.addIfNotNull(openApiUpdater)
    }

    // --- UPLOADED FILES ---

    /**
     * Documents that the handler can receive files with the input [name].
     *
     * [uploadedFiles] can be called multiple times with different [name]s that represent different files, all will be added to the generated documentation.
     *
     * @param name The name of the uploaded files.
     * @param applyUpdates A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun uploadedFiles(name: String, applyUpdates: ApplyUpdates? = null) = apply {
        uploadedFiles(name, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive files with the input [name].
     *
     * [uploadedFiles] can be called multiple times with different [name]s that represent different files, all will be added to the generated documentation.
     *
     * @param name The name of the uploaded files.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun uploadedFiles(name: String, openApiUpdater: OpenApiUpdater? = null) = apply {
        fileUploadList.add(DocumentedFileUpload(name, true))
        requestBodyList.addIfNotNull(openApiUpdater)
    }

    // --- BODY ---

    /**
     * Documents that the handler can receive a request body in the form of the [T].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param applyUpdates A function that allows the underlying Swagger [RequestBody] to modified directly.
     * @param T The class that the handler can receive in its request body.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  body(noinline applyUpdates: ApplyUpdates? = null) = apply {
        body(T::class.java, null, applyUpdates)
    }

    /**
     * Documents that the handler can receive a request body in the form of the [T].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param contentType The content type of the request body.
     * @param applyUpdates A function that allows the underlying Swagger [RequestBody] to modified directly.
     * @param T The class that the handler can receive in its request body.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  body(contentType: String? = null, noinline applyUpdates: ApplyUpdates? = null) = apply {
        body(T::class.java, contentType, applyUpdates)
    }

    /**
     * Documents that the handler can receive a request body in the form of [returnType].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param returnType The class that the handler can receive in its request body.
     * @param contentType The content type of the request body.
     * @param applyUpdates A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun body(returnType: Class<*>, contentType: String? = null, applyUpdates: ApplyUpdates? = null) = apply {
        body(returnType, contentType, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a request body in the form of [returnType].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param returnType The class that the handler can receive in its request body.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun body(returnType: Class<*>, openApiUpdater: OpenApiUpdater? = null) = apply {
        body(returnType, null, openApiUpdater)
    }

    /**
     * Documents that the handler can receive a request body in the form of the input [composition].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param composition The [Composition] that the handler can receive in its request body.
     * @param contentType The content type of the request body.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun body(composition: Composition, contentType: String? = null, openApiUpdater: OpenApiUpdater? = null) = apply {
        body(composition.content, openApiUpdater, contentType, composition.type)
    }

    /**
     * Documents that the handler can receive a request body in the form of [returnType].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param returnType The class that the handler can receive in its request body.
     * @param contentType The content type of the request body.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun body(returnType: Class<*>, contentType: String? = null, openApiUpdater: OpenApiUpdater? = null) = apply {
        val documentedContent = listOf(DocumentedContent(returnType, false, contentType))
        body(documentedContent, openApiUpdater)
    }

    /**
     * Documents that the handler can receive a request body in the form of the input [Schema].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param schema The [Schema] that the handler can receive in its request body.
     * @param contentType The content type of the request body.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun body(schema: Schema<*>, contentType: String, openApiUpdater: OpenApiUpdater? = null) = apply {
        val documentedContent = listOf(DocumentedContent(schema, contentType))
        body(documentedContent, openApiUpdater)
    }

    /**
     * Documents that the handler can receive a request body in the form of the input [DocumentedRequestBody].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param content The [DocumentedContent]s that the handler can receive in its request body.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     * @param contentType The content type of the request body.
     * @param composedType The [ComposedType] of the request body's content.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun body(content: List, openApiUpdater: OpenApiUpdater? = null, contentType: String? = null, composedType: ComposedType = ComposedType.NULL) = apply {
        val documentedBody = DocumentedRequestBody(content, contentType, composedType)
        body(documentedBody, openApiUpdater)
    }

    /**
     * Documents that the handler can receive a request body in the form of the input [DocumentedRequestBody].
     *
     * [body] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param documentedBody The [DocumentedRequestBody] that the handler can receive.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun body(documentedBody: DocumentedRequestBody, openApiUpdater: OpenApiUpdater? = null) = apply {
        componentsUpdaterList.add { it.applyDocumentedRequestBody(documentedBody) }
        requestBodyList.add { it.applyDocumentedRequestBody(documentedBody) }
        requestBodyList.addIfNotNull(openApiUpdater)
    }

    // --- BODY AS BYTES ---

    /**
     * Documents that the handler can receive a request body with the input [contentType] in the form of bytes.
     *
     * [bodyAsBytes] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param contentType The content type of the request body.
     * @param applyUpdates A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun bodyAsBytes(contentType: String? = null, applyUpdates: ApplyUpdates?) = apply {
        bodyAsBytes(contentType, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can receive a request body with the input [contentType] in the form of bytes.
     *
     * [bodyAsBytes] can be called multiple times that represent different request bodies, all will be added to the generated documentation.
     *
     * @param contentType The content type of the request body.
     * @param openApiUpdater A function that allows the underlying Swagger [RequestBody] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun bodyAsBytes(contentType: String? = null, openApiUpdater: OpenApiUpdater? = null) = apply {
        body(ByteArray::class.java, contentType, openApiUpdater)
    }

    // --- JSON ARRAY ---

    /**
     * Documents that the handler can return the input [status] code where the response body will contain `application/json` representing an array of [T].
     *
     * A schema will be added to represent class [T] in the documentation.
     *
     * [jsonArray] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param applyUpdates A function that allows the underlying Swagger [ApiResponse] to modified directly.
     * @param T The class that the documented response body contains.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  jsonArray(status: String, noinline applyUpdates: ApplyUpdates? = null) = apply {
        jsonArray(status, T::class.java, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can return the input [status] code where the response body will contain `application/json` representing an array of [returnType].
     *
     * A schema will be added to represent class [T] in the documentation.
     *
     * [jsonArray] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param returnType The class that the documented response body contains.
     * @param openApiUpdater A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun jsonArray(status: String, returnType: Class<*>, openApiUpdater: OpenApiUpdater? = null) = apply {
        val content = listOf(DocumentedContent(returnType, true, ContentType.JSON))
        val documentedResponse = DocumentedResponse(status, content)
        result(documentedResponse, openApiUpdater)
    }

    // --- JSON ---

    /**
     * Documents that the handler can return the input [status] code where the response body will contain `application/json` in the form of [T].
     *
     * A schema will be added to represent class [T] in the documentation.
     *
     * [json] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param applyUpdates A function that allows the underlying Swagger [ApiResponse] to modified directly.
     * @param T The class that the documented response body contains.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  json(status: String, noinline applyUpdates: ApplyUpdates? = null) = apply {
        json(status, T::class.java, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can return the input [status] code where the response body will contain `application/json` in the form of [returnType].
     *
     * A schema will be added to represent class [returnType] in the documentation.
     *
     * [json] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param returnType The class that the documented response body contains.
     * @param openApiUpdater A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun json(status: String, returnType: Class<*>, openApiUpdater: OpenApiUpdater? = null) = apply {
        val content = listOf(DocumentedContent(returnType, false, ContentType.JSON))
        val documentedResponse = DocumentedResponse(status, content)
        result(documentedResponse, openApiUpdater)
    }

    // --- HTML ---

    /**
     * Documents that the handler can return the input [status] code where the response body will contain `text/html`
     *
     * [html] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param applyUpdates A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun html(status: String, applyUpdates: ApplyUpdates? = null) = apply {
        html(status, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can return the input [status] code where the response body will contain `text/html`
     *
     * [html] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param openApiUpdater A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun html(status: String, openApiUpdater: OpenApiUpdater? = null) = apply {
        val content = listOf(DocumentedContent(String::class.java, false, "text/html"))
        val documentedResponse = DocumentedResponse(status, content)
        result(documentedResponse, openApiUpdater)
    }

    // --- RESULT ---

    /**
     * Documents that the handler can return the input [status] code where the response body will contain [T].
     *
     * [result] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param applyUpdates A function that allows the underlying Swagger [ApiResponse] to modified directly.
     * @param T The class that the documented response body contains.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  result(status: String, noinline applyUpdates: ApplyUpdates? = null) = apply {
        result(status, T::class.java, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can return the input [status] code where the response body will contain [returnType].
     *
     * [result] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param returnType The class that the documented response body contains.
     * @param openApiUpdater A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun result(status: String, returnType: Class<*>? = null, openApiUpdater: OpenApiUpdater? = null) = apply {
        val documentedContent = if (returnType == null || returnType == Unit::class.java) {
            listOf()
        } else {
            listOf(DocumentedContent(returnType, false))
        }
        result(status, documentedContent, openApiUpdater)
    }

    /**
     * Documents that the handler can return the input [status] code where the response body will contain [contentType] in the form of [T].
     *
     * [result] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param applyUpdates A function that allows the underlying Swagger [ApiResponse] to modified directly.
     * @param T The class that the documented response body contains.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmSynthetic
    inline fun  result(status: String, contentType: String?, noinline applyUpdates: ApplyUpdates? = null) = apply {
        result(status, T::class.java, contentType, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can return the input [status] code where the response body will contain [contentType] in the form of [returnType].
     *
     * [result] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param returnType The class that the documented response body contains.
     * @param openApiUpdater A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun result(status: String, returnType: Class<*>?, contentType: String?, openApiUpdater: OpenApiUpdater? = null) = apply {
        val documentedContent = if (returnType == null || returnType == Unit::class.java) {
            listOf()
        } else {
            listOf(DocumentedContent(returnType, false, contentType))
        }
        result(status, documentedContent, openApiUpdater)
    }

    /**
     * Documents that the handler can return the input [status] code where the response body could contain different classes represented by [Composition.OneOf].
     *
     * [result] can be called multiple times with different [status] codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param composition The classes that could be contained in the documented response body.
     * @param applyUpdates A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun result(status: String, composition: Composition.OneOf, applyUpdates: ApplyUpdates? = null) = apply {
        result(status, composition.content, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can return the input [DocumentedResponse].
     *
     * [result] can be called multiple times with different [DocumentedResponse]s that represent different status codes, all will be added to the generated documentation.
     *
     * @param documentedResponse The [DocumentedResponse] to use.
     * @param applyUpdates A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun result(documentedResponse: DocumentedResponse, applyUpdates: ApplyUpdates? = null) = apply {
        result(documentedResponse, createUpdaterIfNotNull(applyUpdates))
    }

    /**
     * Documents that the handler can return the input [status] code where the response body will contain the input [DocumentedContent].
     *
     * [result] can be called multiple times with different [DocumentedResponse]s that represent different status codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param content The [DocumentedContent] that the documented response body contains.
     * @param updater A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun result(status: String, content: DocumentedContent, updater: OpenApiUpdater? = null) = apply {
        result(status, listOf(content), updater)
    }

    /**
     * Documents that the handler can return the input [status] code where the response body could contain the input [DocumentedContent]s.
     *
     * [result] can be called multiple times with different [DocumentedResponse]s that represent different status codes, all will be added to the generated documentation.
     *
     * @param status The status code to document.
     * @param content The [DocumentedContent]s that the documented response body could contain.
     * @param updater A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    fun result(status: String, content: List = listOf(), updater: OpenApiUpdater? = null) = apply {
        val documentedResponse = DocumentedResponse(status, content)
        result(documentedResponse, updater)
    }

    /**
     * Documents that the handler can return the input [DocumentedResponse].
     *
     * [result] can be called multiple times with different [DocumentedResponse]s that represent different status codes, all will be added to the generated documentation.
     *
     * @param documentedResponse The [DocumentedResponse] to use.
     * @param openApiUpdater A function that allows the underlying Swagger [ApiResponse] to modified directly.
     *
     * @return The current [OpenApiDocumentation] for further modification.
     */
    @JvmOverloads
    fun result(documentedResponse: DocumentedResponse, openApiUpdater: OpenApiUpdater? = null) = apply {
        val responseUpdaterList = responseUpdaterListMapping.getOrSetDefault(documentedResponse.status, mutableListOf())
        componentsUpdaterList.add { it.applyDocumentedResponse(documentedResponse) }
        responseUpdaterList.add { it.applyDocumentedResponse(documentedResponse) }
        responseUpdaterList.addIfNotNull(openApiUpdater)
    }

    /** Merge the values of another documentation into this documentation */
    fun apply(other: OpenApiDocumentation) {
        other.isIgnored?.let { this.isIgnored = it }
        this.operationUpdaterList.addAll(other.operationUpdaterList)
        this.requestBodyList.addAll(other.requestBodyList)

        other.parameterUpdaterListMapping.forEach { key, value ->
            if (this.parameterUpdaterListMapping.containsKey(key)) {
                this.parameterUpdaterListMapping[key]!!.addAll(value)
            } else {
                this.parameterUpdaterListMapping[key] = value
            }
        }

        other.responseUpdaterListMapping.forEach { key, value ->
            if (this.responseUpdaterListMapping.containsKey(key)) {
                this.responseUpdaterListMapping[key]!!.addAll(value)
            } else {
                this.responseUpdaterListMapping[key] = value
            }
        }

        this.componentsUpdaterList.addAll(other.componentsUpdaterList)
        this.fileUploadList.addAll(other.fileUploadList)
        this.formParameterList.addAll(other.formParameterList)
    }
}

private fun  MutableList>.add(applyUpdates: ApplyUpdates) {
    val list = this
    list.add(createUpdater(applyUpdates))
}

private fun  MutableList.addIfNotNull(item: T?) {
    val list = this
    item?.let { list.add(item) }
}

private fun  MutableMap.getOrSetDefault(key: K, default: T): T {
    val value = this[key]
    if (value == null) {
        this[key] = default
        return default
    }
    return value
}

private fun List.withContentTypeDefaults() =
        if (this.isEmpty()) listOf(ContentType.AUTODETECT)
        else this




© 2015 - 2025 Weber Informatics LLC | Privacy Policy