Skip to main content

Defining API specification

An API specification is the entry point for code generation. Create a class or object that:

  1. Is annotated with @GenerateApi
  2. Extends ApiSpec. By convention, the class name follows the pattern <Name>ApiSpec (e.g., VinylStoreApiSpec)
  3. Overrides baseUrl

Basic API specification example

import dev.kolibrium.api.core.ApiSpec
import dev.kolibrium.api.ksp.annotations.GenerateApi

@GenerateApi
object MyApiSpec : ApiSpec(baseUrl = "https://api.example.com")

Converting from OpenAPI specifications

If you already have an OpenAPI 3.x specification (JSON or YAML), you can convert it into Kolibrium's annotated Kotlin classes. The annotated classes are the specification in Kolibrium — there is no OpenAPI import or parsing step at runtime. This conversion is currently a manual process; a proper toolchain solution (e.g., a Gradle plugin or CLI that reads the OpenAPI spec and emits annotated Kotlin source files before KSP runs) is not yet available.

Until automated tooling is in place, you can use an LLM with the following prompt to transpile an OpenAPI spec into Kolibrium classes:

You are a code generator that converts OpenAPI 3.x specifications into Kolibrium API module
Kotlin classes. Given an OpenAPI spec (JSON or YAML), produce:

1. **ApiSpec object** — annotated with `@GenerateApi`, extending
`ApiSpec(baseUrl = "<servers[0].url>")`

2. **Request models** for every operation, following these rules:
- Class name: derive from `operationId` (or path+method if missing), PascalCased,
ending with `Request`
- Annotate with the correct HTTP method annotation (`@GET`, `@POST`, `@PUT`, `@PATCH`,
`@DELETE`) with the path
- Annotate with `@Returns(<ResponseType>::class)` using the 200/201 response schema.
Use `Unit::class` if no response body
- If the operation defines both a success and an error response schema, use
`@Returns(success = <SuccessType>::class, error = <ErrorType>::class)`
- Annotate with `@Serializable`
- If the class has properties → `data class`; if no properties → `object`
- Path parameters:
`@Path @Transient val <name>: <type> = <default>`
(map string→String, integer→Int, number→Double, boolean→Boolean)
- Query parameters:
`@Query @Transient val <name>: <type>? = null` (must be nullable)
- Header parameters:
`@Header @Transient val <name>: <type>? = null`.
Use `@Header(name = "X-Actual-Name")` when the header name isn't a valid Kotlin
identifier
- Body parameters (POST/PUT/PATCH):
`var <name>: <type>? = null` — no @Path/@Query/@Header annotation, must be nullable
or have defaults
- Authentication: if the operation has a security requirement, add
`@Auth(type = AuthType.BEARER)`, `@Auth(type = AuthType.BASIC)`,
`@Auth(type = AuthType.API_KEY, headerName = "<name>")`, or
`@Auth(type = AuthType.CUSTOM)` as appropriate

3. **Response models** — `@Serializable data class` for each unique response schema. Reuse
types across operations when schemas match. Use Kotlin types: `String`, `Int`, `Long`,
`Double`, `Boolean`, `List<T>`, nullable where the OpenAPI property is not required.

4. **Shared/reusable schemas** from `components/schemas` should become their own
`@Serializable data class` files.

Package structure:
- ApiSpec → `<basePackage>/`
- Request + Response models → `<basePackage>/models/`

Imports to use:
- `dev.kolibrium.api.core.ApiSpec`
- `dev.kolibrium.api.ksp.annotations.*` (GenerateApi, GET, POST, PUT, PATCH, DELETE,
Returns, Path, Query, Header, Auth, AuthType)
- `kotlinx.serialization.Serializable`
- `kotlinx.serialization.Transient`

Do NOT generate client code — Kolibrium's KSP processor generates that from these
annotations.

Output each file separately with its filename and package declaration.

OpenAPI to Kolibrium mapping reference

OpenAPI ConceptKolibrium Output
paths./foo.get@GET("/foo") ... object FooRequest
paths./foo/{id}.get@GET("/foo/{id}") ... data class GetFooRequest(@Path @Transient val id: Int = 0)
parameters[in=query]@Query @Transient val name: Type? = null
parameters[in=header]@Header @Transient val name: Type? = null
requestBody.content.application/json.schemaBody properties as var name: Type? = null
responses.200.content.*.schema@Returns(SchemaType::class)
responses.200 + responses.4XX schemas@Returns(success = Ok::class, error = Err::class)
No response body@Returns(Unit::class)
securitySchemes.bearer@Auth(type = AuthType.BEARER)
securitySchemes.basic@Auth(type = AuthType.BASIC)
securitySchemes.apiKey@Auth(type = AuthType.API_KEY, headerName = "X-Key-Name")
servers[0].urlApiSpec(baseUrl = "...")

The prompt handles the majority of APIs. Edge cases like allOf/oneOf/anyOf schema composition, multipart/form-data, or file uploads may require manual adjustment. After generation, build the project — Kolibrium's compile-time validation rules will catch any structural errors the transpilation missed.