Skip to content

docs: KDoc generation from OpenAPI descriptions + comprehensive usage guide#26

Open
halotukozak wants to merge 3 commits intomasterfrom
docs/kdoc-and-usage-guide
Open

docs: KDoc generation from OpenAPI descriptions + comprehensive usage guide#26
halotukozak wants to merge 3 commits intomasterfrom
docs/kdoc-and-usage-guide

Conversation

@halotukozak
Copy link
Member

Summary

  • Add KDoc on data class properties from OpenAPI property descriptions
  • Add KDoc on enum constants from x-enum-descriptions extension
  • Add KDoc on API client methods: operation summary + description, @param tags, @return tags
  • Extend Endpoint model with description field, EnumModel with valueDescriptions
  • Extend SpecParser to extract operation.description and x-enum-descriptions
  • Add comprehensive README usage guide: auth config (Bearer/API key/Basic), making requests, error handling with HttpResult, serialization setup, multi-spec configuration

Test plan

  • ModelGeneratorTest — 4 new tests for property KDoc and enum constant KDoc
  • ClientGeneratorTest — 5 new tests for endpoint KDoc with summary/@param/@return
  • README content verified: all 14 sections present
  • Manual: verify KDoc renders correctly in IDE

🤖 Generated with Claude Code

halotukozak and others added 3 commits March 23, 2026 14:08
…changes

- Add description field to Endpoint, valueDescriptions to EnumModel
- Parser extracts operation.description and x-enum-descriptions
- ModelGenerator adds KDoc to properties with descriptions
- ModelGenerator adds per-constant KDoc from valueDescriptions
- Tests verify KDoc presence/absence for properties and enum constants

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Generate KDoc from endpoint summary and description
- Add @param tags for parameters with descriptions
- Add @return tag for non-Unit return types
- No KDoc generated when all descriptions are absent
- Tests verify all KDoc generation scenarios

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Generated Client Usage section with dependencies, client creation, auth examples
- Document Bearer, API Key, Basic, and no-auth constructor patterns
- Add HttpResult/Either error handling guide with HttpError subtype table
- Add serialization setup with SerializersModule for polymorphic types
- Add multi-spec configuration example

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 23, 2026 13:08
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances documentation output from the OpenAPI-driven generators by producing richer KDoc on generated models and client endpoints, and adds a new README usage guide intended to help consumers integrate generated clients.

Changes:

  • Add KDoc generation for model properties (from OpenAPI property descriptions) and enum entries (from x-enum-descriptions).
  • Add KDoc generation for client endpoint methods using operation summary/description plus @param / @return tags.
  • Extend the parsed/spec intermediate model (Endpoint.description, EnumModel.valueDescriptions) and update parsing + tests; expand README with a usage guide.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
core/src/test/kotlin/com/avsystem/justworks/core/gen/ModelGeneratorTest.kt Adds unit tests for property KDoc and enum-entry KDoc generation.
core/src/test/kotlin/com/avsystem/justworks/core/gen/ClientGeneratorTest.kt Adds unit tests for endpoint KDoc generation (summary/description/params/return).
core/src/main/kotlin/com/avsystem/justworks/core/parser/SpecParser.kt Extracts operation.description and parses x-enum-descriptions into EnumModel.valueDescriptions.
core/src/main/kotlin/com/avsystem/justworks/core/model/ApiSpec.kt Extends intermediate models to carry endpoint descriptions and enum value descriptions.
core/src/main/kotlin/com/avsystem/justworks/core/gen/ModelGenerator.kt Emits KDoc on generated data-class properties and enum constants.
core/src/main/kotlin/com/avsystem/justworks/core/gen/ClientGenerator.kt Emits KDoc on generated client endpoint methods including @param and @return.
README.md Adds a comprehensive usage guide for consuming generated clients.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +240 to +241
is List<*> -> enumValues.zip(ext.map { it.toString() }).toMap()
is Map<*, *> -> ext.entries.associate { (k, v) -> k.toString() to v.toString() }
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The x-enum-descriptions handling for list values silently zips by index and will truncate on length mismatch (and also converts nulls to the literal string "null"). This can easily mis-assign descriptions to enum values without any signal. Consider validating that the list size matches schema.enum (fail parsing or at least ignore the extension when sizes differ) and filtering out null description entries instead of toString()-ing them.

Suggested change
is List<*> -> enumValues.zip(ext.map { it.toString() }).toMap()
is Map<*, *> -> ext.entries.associate { (k, v) -> k.toString() to v.toString() }
is List<*> -> {
if (ext.size != enumValues.size) {
emptyMap()
} else {
enumValues.indices
.mapNotNull { idx ->
val description = ext[idx]
description?.toString()?.let { enumValues[idx] to it }
}
.toMap()
}
}
is Map<*, *> -> ext.entries
.mapNotNull { (k, v) ->
v?.toString()?.let { k.toString() to it }
}
.toMap()

Copilot uses AI. Check for mistakes.
.builder(kotlinName, type)
.initializer(kotlinName)
.addAnnotation(AnnotationSpec.builder(SERIAL_NAME).addMember("%S", prop.name).build())
.apply { if (prop.description != null) addKdoc("%L", prop.description) }
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property/enum KDoc is added whenever description != null, which will also emit empty KDoc blocks for "" (or whitespace-only) descriptions coming from specs. Consider using !description.isNullOrBlank() before calling addKdoc(...) to avoid generating meaningless KDoc in the output.

Suggested change
.apply { if (prop.description != null) addKdoc("%L", prop.description) }
.apply { prop.description?.takeIf { it.isNotBlank() }?.let { addKdoc("%L", it) } }

Copilot uses AI. Check for mistakes.
Comment on lines +144 to +176
### Making Requests

Every endpoint becomes a `suspend` function on the client. The return type is `HttpResult<E, T>`, where `E` is the error body type and `T` is the success body type:

```kotlin
val result: HttpResult<JsonElement, List<Pet>> = client.listPets(limit = 10)
```

Path, query, and header parameters map to function arguments. Optional parameters default to `null`:

```kotlin
val result = client.findPets(status = "available", limit = 20)
```

### Error Handling

`HttpResult<E, T>` is a typealias for `Either<HttpError<E>, HttpSuccess<T>>` (using [Arrow](https://arrow-kt.io/)).
Every API call returns a result instead of throwing exceptions:

```kotlin
when (val result = client.getPet(petId = 123)) {
is Either.Right -> {
val pet = result.value.body
println("Found: ${pet.name}")
}
is Either.Left -> when (val error = result.value) {
is HttpError.NotFound -> println("Pet not found")
is HttpError.Unauthorized -> println("Auth required")
is HttpError.Network -> println("Connection failed: ${error.cause}")
else -> println("Error ${error.statusCode}: ${error.body}")
}
}
```
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This README section describes generated endpoints as returning HttpResult<E, T> (Arrow Either) and demonstrates pattern matching on Either.Left/Right, but the current generator produces suspend fun ...: HttpSuccess<T> with a context(Raise<HttpError>) receiver and HttpError is a data class (see ApiClientBaseGenerator/ApiResponseGenerator). The usage guide should be updated to match the actual generated API (how to call endpoints inside a raise context, and how errors are represented).

Copilot uses AI. Check for mistakes.
Comment on lines +102 to +143
### Authentication

The generated constructor signature depends on the security schemes defined in your OpenAPI spec:

**Bearer Token** (single scheme):

```kotlin
val client = PetstoreApi(
baseUrl = "https://api.example.com",
token = { "your-bearer-token" },
)
```

**API Key** (sent as header or query parameter based on the spec):

```kotlin
val client = PetstoreApi(
baseUrl = "https://api.example.com",
myApiKey = { "your-api-key" },
)
```

**HTTP Basic**:

```kotlin
val client = PetstoreApi(
baseUrl = "https://api.example.com",
myAuthUsername = { "user" },
myAuthPassword = { "pass" },
)
```

**No Authentication** (spec has no security schemes):

```kotlin
val client = PetstoreApi(
baseUrl = "https://api.example.com",
)
```

When the spec defines multiple security schemes, the constructor includes a parameter for each one.

Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The authentication guidance here claims the generated constructor signature varies by OpenAPI security schemes (Bearer/API key/Basic/none) and that multiple schemes add multiple constructor params. In the current generator/runtime, the client constructor always includes a token: () -> String and applyAuth() always emits Authorization: Bearer ... (no API key/basic/no-auth support). Either implement the described auth behaviors or adjust this section to reflect the actual capabilities.

Copilot uses AI. Check for mistakes.
implementation("io.ktor:ktor-client-content-negotiation:3.1.1")
implementation("io.ktor:ktor-serialization-kotlinx-json:3.1.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
implementation("io.arrow-kt:arrow-core:2.1.2")
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency versions in this snippet are inconsistent with the versions used elsewhere in the repo (e.g. functional tests and core module use io.arrow-kt:arrow-core:2.2.1.1). Consider updating the README sample to match the repo’s validated versions to reduce copy/paste breakage.

Suggested change
implementation("io.arrow-kt:arrow-core:2.1.2")
implementation("io.arrow-kt:arrow-core:2.2.1.1")

Copilot uses AI. Check for mistakes.
Comment on lines +178 to +197
`HttpError` covers specific HTTP status codes as sealed subtypes:

| Subtype | Status |
|------------------------|--------|
| `BadRequest` | 400 |
| `Unauthorized` | 401 |
| `Forbidden` | 403 |
| `NotFound` | 404 |
| `MethodNotAllowed` | 405 |
| `Conflict` | 409 |
| `Gone` | 410 |
| `UnprocessableEntity` | 422 |
| `TooManyRequests` | 429 |
| `InternalServerError` | 500 |
| `BadGateway` | 502 |
| `ServiceUnavailable` | 503 |
| `Network` | -- |
| `Other` | any |

Network errors (connection timeouts, DNS failures) are caught and wrapped in `HttpError.Network` instead of propagating exceptions.
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HttpError is documented here as having many sealed subtypes for specific status codes (BadRequest/Unauthorized/etc) and a HttpError.Network subtype, but the generated runtime currently defines HttpErrorType enum + HttpError(code, message, type) data class (no per-status sealed hierarchy). This table/description should be rewritten to match the actual error model or the runtime should be extended to provide the documented subtypes.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants