Implementing Code-First API Documentation with Swagger Core and UI
Learn how to implement automated API documentation using Swagger Core and UI in Java. This guide covers the code-first architecture, security boundaries, and how to prevent specification drift.
22 Aug 2025, 18:41 UTC

The Problem: Documentation Drift in Microservices
In fast-moving Java microservice environments, API documentation often lags behind the actual implementation. When developers update a controller method but forget to update a static Wiki or PDF, client teams build integrations against outdated contracts, leading to runtime errors and integration delays. The goal is to create a single source of truth where the code defines the contract.
The Smallest Suitable Design
For teams prioritizing speed of delivery, a Code-First approach using Swagger Core (the implementation of the OpenAPI Specification) is the most efficient starting point. This design integrates documentation directly into the application lifecycle.
- Swagger Core: A library that scans Java classes and annotations at runtime to generate an OpenAPI Specification (OAS) file (typically in JSON or YAML).
- Swagger UI: A decoupled frontend that reads the OAS file and renders an interactive sandbox, allowing users to visualize endpoints and execute requests without writing code.
In this architecture, the Java application serves two primary endpoints: one for the raw specification (e.g., /v3/api-docs) and one for the HTML-based UI (e.g., /swagger-ui.html).
Trust and Data Boundaries
Exposing an API specification is essentially providing a map of your attack surface. To maintain security, you must establish strict trust boundaries:
- Network Isolation: Swagger UI should be restricted to internal VPNs or staging environments. It should not be accessible from the public internet in production.
- Authentication: If the UI must be accessible externally, wrap the Swagger endpoints in a security filter (such as Spring Security) requiring an administrative role.
- Schema Filtering: Use groups or configuration settings to exclude internal-only management endpoints (like Actuator endpoints) from the generated OAS file.
Implementation Example: Java Configuration
To implement this, add the necessary dependencies to your build file and define the API metadata. Below is a conceptual configuration for a Spring-based environment using springdoc-openapi (a common wrapper for Swagger Core).
// Run this configuration within the Application Context
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Order Management API")
.version("1.0.2")
.description("Handles order placement and tracking"));
}
}
// Apply annotations to the Controller to define the contract
@RestController
@RequestMapping("/orders")
@Tag(name = "Orders", description = "Order lifecycle operations")
public class OrderController {
@Operation(summary = "Place a new order", description = "Creates an order record in the DB")
@PostMapping
public ResponseEntity createOrder(@RequestBody OrderRequest request) {
// Implementation logic
}
}
Operational Checks and Verification
To ensure the documentation is accurate and compliant, perform the following checks:
- Schema Validation: Access the
/v3/api-docsendpoint. Copy the JSON output and run it through an OpenAPI validator tool to ensure it adheres to the OAS 3.0/3.1 standard. - Contract Testing: Use the "Try it out" button in Swagger UI. Verify that the
OrderRequestobject accepted by the UI matches the actual JSON structure required by the Java POJO. - Startup Overhead: Monitor memory usage during application startup. In very large APIs, the classpath scanning performed by Swagger Core can increase startup time and heap consumption.
Failure Modes
The primary failure mode of this design is Specification Drift. While the OAS file is generated from code, it relies on annotations. If a developer changes a field type in a Java class but fails to update the @Schema annotation, the documentation will be technically "valid" (it will render) but functionally "incorrect" (it will lie to the consumer).
When to Change the Design
The Code-First approach is ideal for internal tools and rapid prototyping. However, you should migrate to a Design-First architecture if:
- Parallel Development: Client teams need a finalized contract before the backend implementation begins.
- Strict Governance: The API must be reviewed and approved by an architecture board before a single line of code is written.
- Multi-Language Implementation: The same specification must be used to generate server stubs in multiple languages (e.g., Java and Go).
In a Design-First model, the OAS YAML file becomes the source of truth, and code is generated from the file, rather than the file being generated from the code.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.