Defining API specification
An API specification is the entry point for code generation. Create a class or object that:
- Is annotated with
@GenerateApi - Extends
ApiSpec. By convention, the class name follows the pattern<Name>ApiSpec(e.g.,VinylStoreApiSpec) - 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 Concept | Kolibrium 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.schema | Body 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].url | ApiSpec(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.