rgoussu@goussu: ~/library/java/protocols
~/library/java/protocols cat api-documentation.md

API documentation in Java

# OpenAPI, AsyncAPI, protobuf and GraphQL SDL tooling across Spring, Quarkus and Micronaut — springdoc, SmallRye/Micronaut OpenAPI, Springwolf, OpenAPI Generator — and which direction each stack favors.

Conceptsaved 2026-08-09 #java#protocols#documentation#openapi#asyncapi#codegen#frameworks

Overview

The JVM is the home turf of annotation-driven code-first documentation: every stack can decorate the code it already has (@Operation, @Schema, MicroProfile OpenAPI annotations) and emit the spec at build or run time, which is why generate-doc-from-code is the Java default. Contract-first lives one layer up, in the build: OpenAPI Generator's Maven/Gradle plugins turn a hand-authored spec into Spring interfaces, JAX-RS stubs or typed clients. This note maps each doc flavor onto Spring, Quarkus and Micronaut.

Key points

  • OpenAPI code-first is one dependency per stack: springdoc-openapi (Spring), quarkus-smallrye-openapi (Quarkus, MicroProfile OpenAPI), micronaut-openapi (compile time). Each serves the document and a Swagger UI out of the box.
  • OpenAPI contract-first is generator-shaped: OpenAPI Generator's spring target (interfaces + delegate pattern your controllers implement), jaxrs-spec for Quarkus-style resources, and java-micronaut-server; Quarkus adds quarkus-openapi-generator for build-time typed clients from a spec.
  • AsyncAPI has one real code-first citizen: Springwolf — scans Spring Kafka/AMQP/JMS listeners and produces an AsyncAPI document plus UI, springdoc-style. Elsewhere it is contract-first or nothing: AsyncAPI Generator templates for Spring, hand-authored specs validated in CI for Quarkus/Micronaut.
  • gRPC is contract-first by construction: .proto + protobuf-maven-plugin or buf → grpc-java stubs, wrapped by Spring gRPC, quarkus-grpc (Mutiny stubs at build time) and micronaut-grpc; human-readable docs come from protoc-gen-doc or the Buf Schema Registry, never hand-written.
  • GraphQL splits by stack: Spring for GraphQL and Netflix DGS are schema-first (the SDL in resources/graphql/ is the doc); SmallRye GraphQL (Quarkus) is code-first — annotations generate the schema, served at /graphql/schema.graphql; Micronaut wraps graphql-java and leaves the choice open, commonly schema-first.
  • Micronaut's twist: its OpenAPI support runs in the annotation processor — the spec is a build artifact with zero runtime cost, consistent with its compile-time ethos.
  • CI belongs to the spec: whichever direction, lint with Spectral, diff with oasdiff (or buf lint/buf breaking for proto) and publish the rendered doc from the same pipeline — see the trade-off note for why.

Details

Flavor × stack matrix

Flavor Spring Quarkus Micronaut
OpenAPI, code-first springdoc-openapi: runtime scan of MVC/WebFlux annotations → /v3/api-docs + Swagger UI; enrich with swagger-core @Operation/@Schema quarkus-smallrye-openapi: MicroProfile OpenAPI annotations → /q/openapi + Dev UI Swagger; auto-augmented from Jakarta REST metadata at build time micronaut-openapi: annotation processor emits the spec at compile time; swagger-ui/redoc rendering via config
OpenAPI, contract-first OpenAPI Generator spring target — API interfaces + delegate pattern; controllers implement, drift is a compile error OpenAPI Generator jaxrs-spec; quarkus-openapi-generator for typed REST clients generated during augmentation OpenAPI Generator java-micronaut-server / -client targets
AsyncAPI Springwolf (code-first from @KafkaListener/@RabbitListener + UI); AsyncAPI Generator java-spring template for contract-first No first-class extension: hand-author the spec, validate with AsyncAPI CLI in CI; payload contracts via Apicurio/Avro registry Same as Quarkus — spec by hand, registry for payloads
gRPC docs .proto is the contract: protobuf-maven-plugin or buf → grpc-java; Spring gRPC starter wires servers/clients quarkus-grpc generates stubs at build; Dev UI lists services micronaut-grpc on the same codegen
GraphQL Spring for GraphQL: schema-first — SDL files are the source, @SchemaMapping binds resolvers; GraphiQL built in SmallRye GraphQL: code-first — @GraphQLApi annotations → SDL served by the app micronaut-graphql: bring graphql-java either way; commonly schema-first

Choosing a direction on the JVM

Code-first is the path of least resistance everywhere above, and with the build-time stacks (Micronaut, Quarkus) it sheds its classic weakness — the spec exists before deploy, so it can be linted and diffed in CI like a hand-written one. Prefer contract-first when the spec is the product: public APIs, multi-team boundaries where the OpenAPI document is reviewed like code, or polyglot consumers generating their own clients. The delegate pattern (generated interface, hand-written implementation) is the Spring idiom that makes contract-first survivable — never edit generated sources, regenerate on every spec change.

For events, be honest about where the contract lives: if the schema registry (Avro + compatibility rules) is the enforced artifact, AsyncAPI is documentation about it — generate or hand-write it accordingly, and let messaging carry the delivery semantics.

Related