Skip to content

DSL Functions

Reference for InspeKtor's response documentation functions.

responds

Documents a response type for an endpoint.

Kotlin
import io.github.tabilzad.ktor.responds

Signatures

Kotlin
// Basic usage
inline fun <reified T> PipelineContext<*, ApplicationCall>.responds(
    status: HttpStatusCode
)

// With description
inline fun <reified T> PipelineContext<*, ApplicationCall>.responds(
    status: HttpStatusCode, description: String
)

// With content type
inline fun <reified T> PipelineContext<*, ApplicationCall>.responds(
    status: HttpStatusCode, contentType: String
)

// Full options
inline fun <reified T> PipelineContext<*, ApplicationCall>.responds(
    status: HttpStatusCode, description: String, contentType: String
)

Parameters

Parameter Type Required Description
T Type parameter Yes The response body type
status HttpStatusCode Yes HTTP status code
description String No Response description
contentType String No Content type (default: application/json)

Usage Examples

Basic response:

Kotlin
get("/users") {
    responds<List<User>>(HttpStatusCode.OK)
}

With description:

Kotlin
post("/users") {
    responds<User>(HttpStatusCode.Created, description = "User successfully created")
    responds<ErrorResponse>(HttpStatusCode.BadRequest, description = "Invalid user data")
}

With custom content type:

Kotlin
get("/report") {
    responds<ByteArray>(HttpStatusCode.OK, contentType = "application/pdf")
}

Multiple responses:

Kotlin
get("/users/{id}") {
    responds<User>(HttpStatusCode.OK, description = "User found")
    responds<ErrorResponse>(HttpStatusCode.BadRequest, description = "Invalid ID format")
    responds<ErrorResponse>(HttpStatusCode.NotFound, description = "User not found")
    responds<ErrorResponse>(HttpStatusCode.InternalServerError, description = "Server error")
}

Supported Types

Type OpenAPI Schema
User (data class) $ref: '#/components/schemas/User'
List<User> type: array, items: $ref...
Map<String, User> type: object, additionalProperties...
String type: string
Int, Long type: integer
Double, Float type: number
Boolean type: boolean
ByteArray type: string, format: byte

Generated OpenAPI

Kotlin
get("/users/{id}") {
    responds<User>(HttpStatusCode.OK, description = "User found")
    responds<ErrorResponse>(HttpStatusCode.NotFound, description = "User not found")
}

Generates:

YAML
/users/{id}:
  get:
    responses:
      "200":
        description: "User found"
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      "404":
        description: "User not found"
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ErrorResponse'

respondsNothing

Documents a response with no body (e.g., 204 No Content).

Kotlin
import io.github.tabilzad.ktor.respondsNothing

Signatures

Kotlin
// Basic usage
fun PipelineContext<*, ApplicationCall>.respondsNothing(
    status: HttpStatusCode
)

// With description
fun PipelineContext<*, ApplicationCall>.respondsNothing(
    status: HttpStatusCode,
    description: String
)

Parameters

Parameter Type Required Description
status HttpStatusCode Yes HTTP status code
description String No Response description

Usage Examples

Basic usage:

Kotlin
delete("/users/{id}") {
    respondsNothing(HttpStatusCode.NoContent)
}

With description:

Kotlin
delete("/users/{id}") {
    respondsNothing(HttpStatusCode.NoContent, description = "User successfully deleted")
    responds<ErrorResponse>(HttpStatusCode.NotFound, description = "User not found")
}

Common Status Codes

Status Code Use Case
204 No Content Successful DELETE, PUT with no response body
202 Accepted Async operation accepted
301 Moved Permanently Redirect (no body)
304 Not Modified Cache validation

Generated OpenAPI

Kotlin
delete("/users/{id}") {
    respondsNothing(HttpStatusCode.NoContent, description = "User deleted")
}

Generates:

YAML
/users/{id}:
  delete:
    responses:
      "204":
        description: "User deleted"

Best Practices

1. Document All Response Codes

Kotlin
get("/users/{id}") {
    // Success case
    responds<User>(HttpStatusCode.OK)

    // Client errors
    responds<ErrorResponse>(HttpStatusCode.BadRequest)
    responds<ErrorResponse>(HttpStatusCode.Unauthorized)
    responds<ErrorResponse>(HttpStatusCode.Forbidden)
    responds<ErrorResponse>(HttpStatusCode.NotFound)

    // Server errors
    responds<ErrorResponse>(HttpStatusCode.InternalServerError)
}

2. Use Meaningful Descriptions

Kotlin
// Good
responds<User>(HttpStatusCode.OK, description = "Returns the requested user")
responds<ErrorResponse>(HttpStatusCode.NotFound, description = "User with specified ID not found")

// Avoid
responds<User>(HttpStatusCode.OK)  // No description
responds<User>(HttpStatusCode.OK, description = "OK")  // Redundant

3. Use Consistent Error Types

Kotlin
// Define standard error response
data class ErrorResponse(
    val code: String,
    val message: String,
    val details: Map<String, String>? = null
)

// Use consistently
responds<ErrorResponse>(HttpStatusCode.BadRequest)
responds<ErrorResponse>(HttpStatusCode.NotFound)
responds<ErrorResponse>(HttpStatusCode.InternalServerError)

4. Document Collection Responses

Kotlin
// List response
responds<List<User>>(HttpStatusCode.OK)

// Paginated response
responds<Page<User>>(HttpStatusCode.OK)

// Empty list is still 200
responds<List<User>>(HttpStatusCode.OK, description = "Returns users (may be empty)")

5. Place responds Calls at Route Start

Kotlin
get("/users/{id}") {
    // Document responses first
    responds<User>(HttpStatusCode.OK)
    responds<ErrorResponse>(HttpStatusCode.NotFound)

    // Then implementation
    val userId = call.parameters["id"]?.toLongOrNull()
        ?: return@get call.respond(HttpStatusCode.BadRequest)

    val user = userService.findById(userId)
        ?: return@get call.respond(HttpStatusCode.NotFound)

    call.respond(user)
}

Complete Example

Kotlin
import io.github.tabilzad.ktor.responds
import io.github.tabilzad.ktor.respondsNothing
import io.github.tabilzad.ktor.annotations.*
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

@Tag(["Users"])
fun Route.completeUserRoutes() {
    route("/users") {

        @KtorDescription(summary = "List all users")
        get {
            responds<List<User>>(HttpStatusCode.OK, description = "List of all users")
        }

        @KtorDescription(summary = "Create a new user")
        post {
            responds<User>(HttpStatusCode.Created, description = "User created successfully")
            responds<ErrorResponse>(HttpStatusCode.BadRequest, description = "Invalid request body")
            responds<ErrorResponse>(HttpStatusCode.Conflict, description = "Email already exists")

            val request = call.receive<CreateUserRequest>()
            // Implementation
        }

        route("/{id}") {

            @KtorDescription(summary = "Get user by ID")
            get {
                responds<User>(HttpStatusCode.OK, description = "User found")
                responds<ErrorResponse>(HttpStatusCode.BadRequest, description = "Invalid user ID")
                responds<ErrorResponse>(HttpStatusCode.NotFound, description = "User not found")
            }

            @KtorDescription(summary = "Update user")
            put {
                responds<User>(HttpStatusCode.OK, description = "User updated successfully")
                responds<ErrorResponse>(HttpStatusCode.BadRequest, description = "Invalid request")
                responds<ErrorResponse>(HttpStatusCode.NotFound, description = "User not found")

                val request = call.receive<UpdateUserRequest>()
                // Implementation
            }

            @KtorDescription(summary = "Delete user")
            delete {
                respondsNothing(HttpStatusCode.NoContent, description = "User deleted")
                responds<ErrorResponse>(HttpStatusCode.NotFound, description = "User not found")
            }
        }
    }
}