Skip to content

V1 Documenting Routes (Bodies)

Lukas Ruegner edited this page May 29, 2023 · 1 revision

Adding information about request and response bodies.

get("hello", {
    request {
        body<String>() {
            // request body
        }
    }
    response {
        HttpStatusCode.OK to {
            body<String>() {
                // response body
            }
        }
    }
}) {
    // handle request...
}

Basic Body-Specification

body<String>() {
    description = "A brief description of the request body"
    required = true
    example("First", /*value*/) {
        summary = "A short summary of the example"
        description = "A longer description of the example"
    }
    example("Second", /*value*/)
    mediaType(ContentType.Application.Json)
}

body { // body without a schema
    //...
}
  • description - A brief description of the body
  • required - whether the body is required or optional
  • example - specifies a single example for the body. Any amount of examples can be added to a body. See below for more information.
  • mediaType - the media-type of the object (application/json or text/plain by default)

Schema of the Body

Any primitive or more complex Kotlin-class can be used as the schema of a body. If no media-type is specified, a matching one will be picket automatically. The media type for primitive types is currently always text/plain and application/json for complex types.

body<Int>()
body<Pet>()
body<List<Pet>>()

data class Pet(
    val id: Int,
    val name: String,
    val tag: String
)

Types can alternatively also be provided as a normal function-parameter, tough this method has some limitations, especially when it comes to generic-types.

body(Int::class)
body(Pet::class)
body(Array<Pet>::class)

Swagger @Schema-Annotation

Classes and fields can be annotated with the @Schema and @ArraySchema annotations to add information such as an description, example-values, a title for the schema or whether a field is nullable.

The tested and fully supported features of the @Schema-annotation are: title, description, nullable, format, example, minLength, maxLength, minimum, maximum, minItems, maxItems, uniqueItems.

Example:

@Schema(title = "The Schema for a person")
data class Person(
    
    @field:Schema(description = "the name of the person", required = true)
    val name: String,
    
    @field:Schema(description = "the age of the person in years", nullable = true)
    val age: Int?
    
)

For more information, see /~https://github.com/victools/jsonschema-generator/tree/main/jsonschema-module-swagger-2 or /~https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Annotations#schema

Multipart-Bodies

The definition for multipart-bodies is similar to that of normal bodies.

multipartBody {
    description = "A brief description of the request body"
    required = true
    mediaType(ContentType.MultiPart.FormData)
    part<File>("myImage") {
        mediaTypes = setOf(
            ContentType.Image.PNG,
            ContentType.Image.JPEG,
            ContentType.Image.GIF
        )
    }
    part<Metadata>("myMetadata")
}
//...
data class Metadata(
    val format: String,
    val location: Coords
)
data class Coords(
    val lat: Float,
    val long: Float
)
  • description - A brief description of the body
  • required - whether the body is required or optional
  • mediaType - the media-type of the object (multipart/formdata by default)
  • part - one part of the body with the given name and type/schema (use java.io.File for file-uploads/downloads)
    • mediaTypes - specify custom valid content-types for the part
    • headers - include custom headers for the part

Custom Schemas

Custom Predefined Schemas

Schemas can be pre-configured in the plugin-configuration and then referenced by an id.

Configuration

install(SwaggerUI) {
	schemas {
    	json("myCustomJsonSchema") {
        	"""
            {
                "type": "object",
                "properties": { ... }
            }
        	""".trimIndent()
        }
        openApi("myCustomSchema") {
            Schema<Any>().apply { /*...*/ }
        }
        remote("myRemoteSchema", "http://localhost:8080/schemas/myschema.json")
    }
}
//...
body(obj("myCustomJsonSchema"))
body(obj("myCustomSchema"))
body(obj("myRemoteSchema"))
multipartBody {
    part("myPart", obj("myCustomSchema"))
}
  • json - provide the schema as a json-schema
  • openApi - provide the schema as a "Schema"-Object
  • remote - the schema can be found at the given url. Only the reference is added to the OpenApi-Spec, not the complete schema.

Usage

Custom schemas can be referenced by their id as the body of an request or response.

body("myCustomJsonSchema") // "myCustomJsonSchema" is the schema of the body
body(obj("myRemoteSchema")) // same as "body("myRemoteSchema")"

body(array("myCustomSchema")) // body is an array with elements of in the schema "myCustomSchema"

multipartBody {
    part("myPart", obj("myCustomSchema")) // same as part("myPart", "myCustomSchema")
}

Custom Schema-Builder

A custom builder for converting a Type to a json-schema can also be provided.

install(SwaggerUI) {
	schemas {
        jsonSchemaBuilder { type -> myJsonSchemaBuilder(type) }
    }
}

If null is returned for a type, the default built-in json-schema-builder is used for this type instead.

Media Types

A request/response body can have any amount of supported media types. If no media type is specified and a schema exists, a media type will automatically be chosen (usually "application/json" for complex models and arrays and "text/plain" for everything else)

body<Pet>() {
    mediaType(ContentType.Application.Json)
    mediaType(ContentType.Application.Xml)
}

body {
    mediaType(ContentType.Image.PNG)
    mediaType(ContentType.Image.JPEG)
    mediaType(ContentType.Image.SVG)
}

Body Examples

Example objects can be provided with each body.

body<Pet>() {
    example("First", Pet(1, "Chloe", "cat")) {
        summary = "A short summary of the example"
        description = "A longer description of the example"
    }
    example("Second", Pet(2, "Oliver", "dog"))
}

body<List<Pet>>() {
    example("Example",  listOf(
        Pet(1, "Chloe", "cat"),
        Pet(2, "Oliver", "dog")
    ))
}

data class Pet(
    val id: Int,
    val name: String,
    val tag: String
)
example(name: String, value: Any) {
    ...
}
  • name - each example must have a new
  • value - the example value as a kotlin/java object
  • summary - A short summary of the example
  • description - A longer description of the example

Examples can also be auto-generated via the help of the annotations @Example or @Schema. Both can be added to fields of the models and no additional example has to be specified. Examples specifically provided with each route have higher priority than examples generated from annotations.

Example using the @Example-Annotations:

import io.github.smiley4.ktorswaggerui.dsl.Example

data class Person(

    @Example("Steve")
    val name: String,

    @Example("42")
    val age: Int,

    @Example("172")
    val size: Float,

    @Example("false")
    val robot: Boolean,
)

Example using the @Schema-Annotation:

import io.swagger.v3.oas.annotations.media.Schema

data class Person(

    @field:Schema(example = "Steve")
    val name: String,

    @field:Schema(example = "42")
    val age: Int,

    @field:Schema(example = "172")
    val size: Float,

    @field:Schema(example = "false")
    val robot: Boolean
)
Clone this wiki locally