Technology Aug 25, 2026 · 4 min read

Baklava: Generate API Documentation and Type-Safe Clients from Scala Routing Tests

API documentation has a reliability problem. The code gets updated; the OpenAPI spec gets forgotten. The spec gets updated; the TypeScript client doesn't regenerate. By the time an enterprise client asks for your API contract, the document you hand them describes a system that no longer exists. Bakl...

DE
DEV Community
by Katarzyna Kozłowska
Baklava: Generate API Documentation and Type-Safe Clients from Scala Routing Tests

API documentation has a reliability problem. The code gets updated; the OpenAPI spec gets forgotten. The spec gets updated; the TypeScript client doesn't regenerate. By the time an enterprise client asks for your API contract, the document you hand them describes a system that no longer exists. Baklava, an open-source library by Iterators, solves this structurally: documentation is generated from the tests that verify your actual API behaviour, so it cannot drift.

The problem

Documentation drift is the default state of any API that lives long enough. The causes are well-understood: docs and code are maintained separately, documentation updates require extra discipline at every PR, and no automated check catches a route signature change that wasn't reflected in the OpenAPI file.

The consequence is real. Clients building against a stale spec hit integration errors in production. Internal teams onboarding to a service spend hours reconciling the documented contract with actual behaviour. TypeScript front-ends break when an API response field changes without a corresponding client update. The problem compounds as the API grows.

The solution

Baklava integrates into your existing test suite. When routing tests run, baklava observes each request and response, infers the API surface, and generates documentation as a test output, not as a separate build step, not as a manually-maintained file.

In baklava, the test is the documentation spec. Instead of a standard assertion block, each route is defined with path(), supports(), and onRequest() scenarios that both verify the API behaviour and describe it for documentation output:

​`// The test IS the documentation spec
class UserApiSpec extends AnyFunSpec
with BaklavaPekkoHttp[Unit, Unit, ScalatestAsExecution]
with BaklavaScalatest[Route, ToEntityMarshaller, FromEntityUnmarshaller] {

path("/users/{userId}")(
supports(
GET,
pathParameters = pLong,
summary = "Get user by ID"
)(
onRequest(pathParameters = 1L)
.respondsWithUser
.assert { ctx =>
ctx.performRequest(routes).body.id shouldBe 1L
},
onRequest(pathParameters = 999L)
.respondsWithErrorResponse
.assert { ctx => ctx.performRequest(routes) }
)
)
}
// Running sbt test generates OpenAPI, HTML, and TypeScript, automatically.
// If the test breaks, the docs don't publish.`

If the test passes, the documentation is accurate, because the test verified the behaviour the documentation describes. If the route changes and the test breaks, the documentation won't publish until the test is fixed. Documentation drift becomes structurally impossible.

Coverage

Baklava supports the two dominant Scala HTTP frameworks, Pekko HTTP and http4s, and integrates with ScalaTest, Specs2, and MUnit. Seven output formats, each an independent SBT dependency, auto-discovered via reflection:

  • Simple HTML: self-contained, browsable human-readable documentation
  • OpenAPI: OpenAPI 3.0.1 spec with SwaggerUI integration for Pekko HTTP, the standard contract format for enterprise API integrations
  • TS-REST: TypeScript npm package using ts-rest and Zod for type-safe API contracts
  • oRPC Contract Format: TypeScript package with oRPC contracts, Zod validators, and a ready-made client factory
  • TypeScript Fetch Client: plain-TypeScript client using the browser/Node fetch API, no external runtime dependencies
  • Postman: Postman Collection v2.1, importable into Postman and Insomnia
  • sttp client: Scala sttp-client4 request builders for every endpoint

Scala 2.13 and Scala 3, JDK 11+. Baklava also integrates with kebs: if your project already uses kebs for domain type derivation, baklava picks up the schema definitions automatically.

Adoption and maintenance

Baklava v1.4.0 was released in May 2026 and is actively maintained by Iterators. Apache 2.0 license.

The approach, deriving documentation from tests rather than maintaining it separately, is not new in principle, but prior implementations in the Scala ecosystem typically required significant test instrumentation or source-level annotation. Baklava keeps the overhead minimal: mix in a trait, run your existing tests, get documentation as output.

Context

OpenAPI generation tools for Scala generally fall into two camps: annotate source code (tapir, endpoints4s) or maintain separate spec files. Source annotation couples documentation concerns into routing logic and requires adopting the library's routing model. Separate spec files require discipline. Baklava is positioned differently: it uses the test suite as the source of truth, which works with any routing code that produces testable HTTP responses, so no migration of existing routes is required.

As Łukasz Sowa, Managing Partner at Iterators, puts it: "Integration tests are one of the most overlooked types of tests. 'Units pass, I'm ok!' until they aren't and it isn't. The amount of work to get them right used to be the usual excuse; now AI can do the heavy lifting, which removes it. But integration tests are more than a good night's sleep pill. They're the ultimate spec for how the outside world interacts with your system. With baklava, we turn integration tests into integration artifacts, for many kinds of consumers."

Baklava is open source under the Apache 2.0 license. GitHub: https://github.com/theiterators/baklava

DE
Source

This article was originally published by DEV Community and written by Katarzyna Kozłowska.

Read original article on DEV Community
Back to Discover

Reading List