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

io.javalin.openapi.OpenApiAnnotations.kt Maven / Gradle / Ivy

There is a newer version: 6.4.0
Show newest version
/**
 * Internal copy of https://github.com/tipsy/javalin/blob/master/javalin/src/main/java/io/javalin/plugin/openapi/annotations/AnnotationApi.kt file.
 * In the future it might be replaced with a better impl.
 */

package io.javalin.openapi

import io.javalin.openapi.HttpMethod.GET
import io.javalin.openapi.Visibility.PUBLIC
import java.lang.annotation.Repeatable
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FIELD
import kotlin.annotation.AnnotationTarget.FUNCTION
import kotlin.annotation.AnnotationTarget.PROPERTY_GETTER
import kotlin.annotation.AnnotationTarget.PROPERTY_SETTER
import kotlin.reflect.KClass

/**
 * Provide metadata for the generation of the open api documentation to the annotated Handler.
 * Source: [Specification](https://swagger.io/specification/)
 */
@Repeatable(value = OpenApis::class)
@Target(CLASS, FIELD, FUNCTION)
@Retention(RUNTIME)
annotation class OpenApi(
    /** The described path */
    val path: String,
    /** List of methods to describe **/
    val methods: Array = [GET],
    /** Schema version **/
    val versions: Array = ["default"],
    /** Ignore the endpoint in the open api documentation */
    val ignore: Boolean = false,
    /** An optional, string summary, intended to apply to all operations in this path. **/
    val summary: String = NULL_STRING,
    /** An optional, string description, intended to apply to all operations in this path. **/
    val description: String = NULL_STRING,
    /**
     * Unique string used to identify the operation.
     * The id MUST be unique among all operations described in the API.
     * The operationId value is case-sensitive.
     *
     * You can also use [OpenApiOperation.AUTO_GENERATE]
     * if you want to generate the operationId automatically using the method name.
     **/
    val operationId: String = NULL_STRING,
    /** Declares this operation to be deprecated. Consumers SHOULD refrain from usage of the declared operation. **/
    val deprecated: Boolean = false,
    /**
     *  A list of tags for API documentation control.
     *  Tags can be used for logical grouping of operations by resources or any other qualifier.
     **/
    val tags: Array = [],
    /** Describes applicable cookies */
    val cookies: Array = [],
    /** Describes applicable headers */
    val headers: Array = [],
    /** Describes applicable path parameters */
    val pathParams: Array = [],
    /** Describes applicable query parameters */
    val queryParams: Array = [],
    /** Describes applicable form parameters */
    val formParams: Array = [],
    /**
     * The request body applicable for this operation.
     * The requestBody is only supported in HTTP methods where the HTTP 1.1 specification RFC7231 has explicitly defined semantics for request bodies.
     * In other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers.
     */
    val requestBody: OpenApiRequestBody = OpenApiRequestBody([]),
    /** Describes applicable callbacks */
    val callbacks: Array = [],
    // val composedRequestBody: OpenApiComposedRequestBody = OpenApiComposedRequestBody([]), ?
    /** The list of possible responses as they are returned from executing this operation. */
    val responses: Array = [],
    /** A declaration of which security mechanisms can be used for this operation. */
    val security: Array = [],
)

fun OpenApi.getFormattedPath(): String =
    when {
        !path.startsWith("/") -> "/$path"
        else -> path
    }

/** Utility annotation to aggregate multiple [OpenApi] instances */
@Target(CLASS, FIELD, FUNCTION)
@Retention(RUNTIME)
annotation class OpenApis(
    val value: Array = []
)

@Target()
@Retention(RUNTIME)
annotation class OpenApiResponse(
    val status: String,
    val content: Array = [],
    val description: String = NULL_STRING,
    val headers: Array = [],
)

@Target()
@Retention(RUNTIME)
annotation class OpenApiParam(
    val name: String,
    val type: KClass<*> = String::class,
    val description: String = NULL_STRING,
    val deprecated: Boolean = false,
    val required: Boolean = false,
    val allowEmptyValue: Boolean = false,
    val example: String = ""
)

@Target()
@Retention(RUNTIME)
annotation class OpenApiRequestBody(
    val content: Array,
    val required: Boolean = false,
    val description: String = NULL_STRING
)

@Target()
@Retention(RUNTIME)
annotation class OpenApiCallback(
    val name: String,
    val url: String,
    val method: HttpMethod,
    val summary: String = NULL_STRING,
    val description: String = NULL_STRING,
    val requestBody: OpenApiRequestBody,
    val responses: Array
)

@Target()
@Retention(RUNTIME)
annotation class OpenApiContent(
    val from: KClass<*> = NULL_CLASS::class,
    val mimeType: String = ContentType.AUTODETECT,
    val type: String = NULL_STRING,
    val format: String = NULL_STRING,
    val properties: Array = [],
    val example: String = NULL_STRING,
    val exampleObjects: Array = [],
)

@Target()
@Retention(RUNTIME)
annotation class OpenApiContentProperty(
    val name: String,
    val isArray: Boolean = false,
    val type: String,
    val format: String = NULL_STRING
)

@Target()
@Retention(RUNTIME)
annotation class OpenApiSecurity(
    val name: String,
    val scopes: Array = []
)

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiIgnore

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiRequired

@Target(CLASS, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiName(
    val value: String
)

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiExample(
    val value: String = NULL_STRING,
    val objects: Array = []
)

@Target(ANNOTATION_CLASS)
@Retention(RUNTIME)
annotation class OpenApiExampleProperty(
    val name: String = NULL_STRING,
    val value: String = NULL_STRING,
    val objects: Array = []
)

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
@CustomAnnotation
annotation class OpenApiNullable(
    val nullable: Boolean = true
)

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, CLASS)
@Retention(RUNTIME)
annotation class OpenApiDescription(
    val value: String
)

enum class Nullability {
    NULLABLE,
    NOT_NULL,
    AUTO
}

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiNumberValidation(
    val minimum: String = NULL_STRING,
    val exclusiveMinimum: Boolean = false,
    val maximum: String = NULL_STRING,
    val exclusiveMaximum: Boolean = false,
    val multipleOf: String = NULL_STRING
)

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiStringValidation(
    val minLength: String = NULL_STRING,
    val maxLength: String = NULL_STRING,
    val format: String = NULL_STRING,
    val pattern: String = NULL_STRING
)

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiArrayValidation(
    val minItems: String = NULL_STRING,
    val maxItems: String = NULL_STRING,
    val uniqueItems: Boolean = false
)

@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiObjectValidation(
    val minProperties: String = NULL_STRING,
    val maxProperties: String = NULL_STRING,
)

@Target(CLASS, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Retention(RUNTIME)
annotation class OpenApiPropertyType(
    val definedBy: KClass<*>,
    val nullability: Nullability = Nullability.AUTO
)

enum class Visibility(val priority: Int) {
    PUBLIC(4),
    DEFAULT(3),
    PROTECTED(2),
    PRIVATE(1)
}

@Target(CLASS)
@Retention(RUNTIME)
annotation class OpenApiByFields(
    val value: Visibility = PUBLIC
)

/** Null class because annotations do not support null values */
@Suppress("ClassName")
class NULL_CLASS

/** Null string because annotations do not support null values */
const val NULL_STRING = "-- This string represents a null value and shouldn't be used --"

object OpenApiOperation {
    /** Value to use for auto-generate operationId */
    const val AUTO_GENERATE = "-- Auto-generate operationId on the fly. If you see this message you are either inspecting via debugger or something went wrong --"
}

object ContentType {
    const val JSON = "application/json"
    const val HTML = "text/html"
    const val FORM_DATA_URL_ENCODED = "application/x-www-form-urlencoded"
    const val FORM_DATA_MULTIPART = "multipart/form-data"
    const val AUTODETECT = "AUTODETECT - Will be replaced later"
}

enum class ComposedType {
    NULL,
    ANY_OF,
    ONE_OF;
}

enum class HttpMethod {
    POST,
    GET,
    PUT,
    PATCH,
    DELETE,
    HEAD,
    OPTIONS,
    TRACE;
}

class OpenApiLoader {

    fun loadOpenApiSchemes(): Map =
        loadVersions().associateWith { loadVersion(it) ?: "{}" }

    fun loadVersions(): Set =
        OpenApiLoader::class.java.getResourceAsStream("/openapi-plugin/.index")
            ?.readAllBytes()
            ?.decodeToString()
            ?.split("\n")
            ?.asSequence()
            ?.map { it.trim() }
            ?.map { it.removePrefix("openapi-") }
            ?.map { it.removeSuffix(".json") }
            ?.toSet()
            ?: emptySet()

    fun loadVersion(version: String): String? =
        OpenApiLoader::class.java.getResource("/openapi-plugin/openapi-$version.json")?.readText()

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy