
Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: September 10, 2024
API documentation is a crucial aspect of any web service, providing a clear and structured way for developers to understand and interact with any API.
OpenAPI (formerly known as Swagger) is a widely adopted standard for creating comprehensive API documentation.
In this article, we’ll walk through the steps to set up a Kotlin project using Ktor and integrate OpenAPI to generate and display API documentation.
Before starting with the implementation, we’ll need to set up our Ktor project’s structure and add the required dependencies.
The first step is to create a new Kotlin project in any IDE, such as IntelliJ IDEA. We’ll have to select Kotlin and Ktor as our project type.
To support OpenAPI, we need to include the required plugins and dependencies for Ktor and OpenAPI. We’ll also have to include the swagger-codegen-generators dependency that will be in charge of generating the documentation site:
plugins {
id("io.ktor.plugin") version "2.3.11"
...
}
dependencies {
implementation("io.ktor:ktor-server-core:$ktor_version")
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("io.ktor:ktor-server-swagger:$ktor_version")
implementation("io.ktor:ktor-server-openapi:$ktor_version")
implementation("io.ktor:ktor-server-cors:$ktor_version")
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
implementation("io.swagger.codegen.v3:swagger-codegen-generators:$swagger_codegen_version")
testImplementation("io.ktor:ktor-server-test-host:$ktor_version")
...
}
Now that the project is properly set up, we can start with the implementation by creating the documentation file where we can define the details of each endpoint of the API.
OpenAPI allows us to define the description of each service available in our API using a YAML file descriptor.
We’ll take as a case study an API to create and read Products of any generic store:
openapi: "3.0.3"
info:
title: "Products API"
description: "API to create and retrieve Products"
version: "1.0.0"
servers:
- url: "http://0.0.0.0:8080"
paths:
/product:
post:
description: "Creates a new product"
requestBody:
description: "A JSON object that represents a product"
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Product"
responses:
"201":
description: "Created"
content:
text/plain:
schema:
type: "string"
examples:
Example#1:
value: "Product saved successfully"
/product/{id}:
get:
description: "Returns a product by the ID"
parameters:
- name: "id"
in: "path"
required: true
schema:
type: "string"
responses:
"200":
description: "OK"
content:
'*/*':
schema:
$ref: "#/components/schemas/Product"
components:
schemas:
Product:
type: "object"
properties:
id:
type: "integer"
format: "int32"
name:
type: "string"
price:
type: "number"
format: "double"
Working with OpenAPI and Ktor also allows the generation of the YAML documentation dynamically from the code using annotations to specify the endpoint information.
Let’s create the main application file that will serve as the entry point for our Ktor application. This file will set up the basic structure, including defining the Product data class and initializing the server:
@Serializable
data class Product(val id: Int, val name: String, val price: Double)
fun main(args: Array<String>) {
embeddedServer(Netty, port = 8080, module = Application::main).start(wait = true)
}
fun Application.main() {
val productStorage = mutableListOf<Product>()
productStorage.addAll(
arrayOf(
Product(1, "Laptop", 999.99),
Product(2, "Smartphone", 499.99)
)
)
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
})
}
install(CORS) {
anyHost()
allowHeader(HttpHeaders.ContentType)
}
}
To make the API documentation accessible and user-friendly, we’ll enable Swagger UI. This tool provides a graphical interface for interacting with the API endpoints:
fun Application.main() {
routing {
// API endpoints
swaggerUI(path = "swagger", swaggerFile = "openapi/documentation.yaml") {
version = "4.15.5"
}
}
}
This configuration will make Swagger UI available at the /swagger path, using the specified OpenAPI documentation.
Finally, we’ll implement the actual API endpoints as per the product API documentation. These endpoints allow users to retrieve and create products:
fun Application.main() {
// Swagger UI setup
routing {
get("/product/{id}") {
val id = call.parameters["id"]
val product: Product = productStorage.find { it.id == id!!.toInt() }!!
call.respond(product)
}
post("/product") {
val product = call.receive<Product>()
productStorage.add(product)
call.respondText("Product saved successfully", status = HttpStatusCode.Created)
}
openAPI(path="openapi", swaggerFile = "openapi/documentation.yaml") {
codegen = StaticHtmlCodegen()
}
}
}
With the configurations in place, we can run the application by executing the main function in Application.kt. In IntelliJ IDEA, we can do this by clicking the run icon next to the main function or by using the terminal with the command ./gradlew run.
As we have defined the proper route to SwaggerUI, we can now navigate to http://localhost:8080/swagger to see the available endpoints. For example, we can create a new product by making a POST request to the /product endpoint as follows:
Now, to check if the product was created correctly, we can use a GET request to the /product endpoint:
We should see the response from the server with the data of the product we have created before:
Finally, we can navigate to the following URL: http://localhost:8080/openapi, where the complete API documentation has been generated:
From this documentation, we can check implementation examples for a variety of SDKs.
In this article, we’ve demonstrated how to set up a Kotlin project using Ktor and integrate OpenAPI (Swagger) to generate and display API documentation. This setup provides a clear and interactive way for developers to understand and interact with any API.