# gradle-restdoc-generator A Gradle plugin that automatically generates REST API documentation from Spring Boot `@RestController` classes. It scans your controllers using reflection and Javadoc parsing to produce JSON metadata, OpenAPI 3.0.3 specifications, unified spec bundles, and Postman collections. The plugin supports rich documentation through custom Javadoc tags like `@response`, `@group`, `@auth`, `@header`, and `@error`. The plugin intelligently handles Spring Data pagination (`Pageable`/`Page`), automatic unwrapping of wrapper types like `ApiResult`, complex query parameter objects, enum values extraction, required field detection via validation annotations (`@NotNull`, `@NotBlank`, `@NotEmpty`), and comprehensive error code documentation from exception classes. It generates meaningful operation IDs based on method names for better code generator compatibility. ## Installation Configure the plugin in your Gradle build file to enable automatic REST API documentation generation. ```groovy // build.gradle - Using buildscript buildscript { repositories { maven { url 'https://jitpack.io' } } dependencies { classpath 'com.github.Axim-one:gradle-restdoc-generator:2.1.4' } } apply plugin: 'gradle-restdoc-generator' // Alternative: settings.gradle + plugins DSL // settings.gradle pluginManagement { repositories { maven { url 'https://jitpack.io' } gradlePluginPortal() } resolutionStrategy { eachPlugin { if (requested.id.id == 'gradle-restdoc-generator') { useModule("com.github.Axim-one:gradle-restdoc-generator:${requested.version}") } } } } // build.gradle plugins { id 'gradle-restdoc-generator' version '2.1.4' } ``` ## Basic Configuration Configure the `restMetaGenerator` extension with required properties: document output path, base package to scan, and service identifier. ```groovy // build.gradle restMetaGenerator { // Required properties documentPath = 'build/docs' // Output directory for generated docs basePackage = 'com.example' // Package to scan for @RestController serviceId = 'my-service' // Unique service ID (used as JSON filename) // Service information serviceName = 'My Service' // Display name (OpenAPI title) apiServerUrl = 'https://api.example.com' // Base URL (OpenAPI servers) serviceVersion = 'v1.0' // API version (use '' to omit version prefix) introductionFile = 'docs/introduction.md' // Markdown file for service description // Error handling classes errorCodeClass = 'com.example.exception.ErrorCode' errorResponseClass = 'com.example.dto.ApiErrorResponse' debug = false } ``` ## Authentication Configuration - API Key Configure API Key authentication which maps to OpenAPI 3.0 `apiKey` security scheme and Postman `apikey` auth type. ```groovy restMetaGenerator { documentPath = 'build/docs' basePackage = 'com.example' serviceId = 'my-service' auth { type = 'apiKey' // Or 'token' (backward compatible alias) headerKey = 'Access-Token' // Header/parameter name value = '{{accessToken}}' // Token value (Postman variable syntax) in = 'header' // Location: 'header', 'query', or 'cookie' descriptionFile = 'docs/auth.md' // Optional markdown description } debug = false } // Generated OpenAPI securitySchemes: // { // "type": "apiKey", // "in": "header", // "name": "Access-Token" // } ``` ## Authentication Configuration - Bearer Token Configure Bearer token authentication for JWT-based APIs, mapping to OpenAPI 3.0 `http` security scheme with `bearer` scheme. ```groovy restMetaGenerator { documentPath = 'build/docs' basePackage = 'com.example' serviceId = 'my-service' auth { type = 'http' scheme = 'bearer' bearerFormat = 'JWT' // Optional hint for token format value = '{{accessToken}}' descriptionFile = 'docs/auth.md' } debug = false } // Generated OpenAPI securitySchemes: // { // "type": "http", // "scheme": "bearer", // "bearerFormat": "JWT" // } ``` ## Authentication Configuration - Basic Auth Configure HTTP Basic authentication for username/password APIs. ```groovy restMetaGenerator { documentPath = 'build/docs' basePackage = 'com.example' serviceId = 'my-service' auth { type = 'http' scheme = 'basic' value = '{{username}}:{{password}}' descriptionFile = 'docs/auth.md' } debug = false } // Generated OpenAPI securitySchemes: // { // "type": "http", // "scheme": "basic" // } ``` ## Custom Headers Configuration Add common HTTP headers that apply to all API endpoints in the generated documentation. ```groovy restMetaGenerator { documentPath = 'build/docs' basePackage = 'com.example' serviceId = 'my-service' // Add common headers header('X-Request-Id', '', 'Request tracking ID') header('X-Tenant-Id', 'default', 'Multi-tenant identifier') header('Accept-Language', 'ko-KR', 'Preferred response language') debug = false } // Headers appear in spec-bundle.json service.headers array ``` ## Postman Environment Configuration Configure multiple Postman environments with environment-specific variables for seamless API testing across different stages. ```groovy restMetaGenerator { documentPath = 'build/docs' basePackage = 'com.example' serviceId = 'my-service' // Postman API credentials for auto-sync postmanApiKey = 'PMAK-xxx' postmanWorkSpaceId = 'workspace-id' // Environment configurations environment('DEV') { variable('base_url', 'https://dev.api.example.com') variable('accessToken', 'dev-test-token') variable('timeout', '30000') } environment('STAGING') { variable('base_url', 'https://staging.api.example.com') variable('accessToken', '') variable('timeout', '10000') } environment('PROD') { variable('base_url', 'https://api.example.com') variable('accessToken', '') variable('timeout', '5000') } debug = false } ``` ## Javadoc Tags for API Documentation Use custom Javadoc tags to enrich your API documentation with response codes, grouping, authentication requirements, and error handling. ```java /** * Retrieves detailed user information by ID. * * @param userId User's unique identifier * @return User details including profile and permissions * @response 200 Success * @response 404 User not found * @group User Management * @auth true * @header X-Request-Id Request tracking ID for debugging * @error UserNotFoundException * @throws AuthenticationException */ @GetMapping(name = "Get User Details", value = "/{userId}") public UserDto getUser(@PathVariable Long userId) { return userService.findById(userId); } /** * Searches users with complex filter criteria. * * @param search Search parameters object * @return List of matching users * @response 200 Success * @group User Management */ @GetMapping(name = "Search Users", value = "/search") public List searchUsers(UserSearchRequest search) { return userService.search(search); } // Supported Javadoc tags: // @param {name} {description} - Parameter documentation // @return {description} - Return value documentation // @response {code} {description} - HTTP response status and description // @group {name} - API grouping (maps to Postman folders) // @auth true - Marks endpoint as requiring authentication // @header {name} {description} - Custom header documentation // @error {ExceptionClass} - Links error group to endpoint // @throws {ExceptionClass} - Same as @error (standard Javadoc) // @className {name} - Override generated class name ``` ## Error Code Documentation Define error codes in exception classes for automatic scanning and documentation. The plugin extracts `public static final ErrorCode` fields from exception classes. ```java // Exception class with error codes public class UserNotFoundException extends RuntimeException { public static final ErrorCode USER_NOT_FOUND = new ErrorCode("USER_001", "error.user.notfound"); public static final ErrorCode USER_DELETED = new ErrorCode("USER_002", "error.user.deleted"); public static final ErrorCode USER_SUSPENDED = new ErrorCode("USER_003", "error.user.suspended"); public UserNotFoundException(ErrorCode errorCode) { super(errorCode.getMessage()); } } // Error response DTO (specify via errorResponseClass) public class ApiErrorResponse { private int status; private String code; private String message; private String timestamp; private String path; } // build.gradle configuration restMetaGenerator { documentPath = 'build/docs' basePackage = 'com.example' serviceId = 'my-service' errorCodeClass = 'com.example.exception.ErrorCode' errorResponseClass = 'com.example.dto.ApiErrorResponse' debug = false } // Generated error/errors.json: // { // "group": "User Not Found", // "exception": "UserNotFoundException", // "status": 404, // "codes": [ // { "code": "USER_001", "name": "USER_NOT_FOUND", "message": "User not found" }, // { "code": "USER_002", "name": "USER_DELETED", "message": "User deleted" } // ] // } ``` ## API Exclusion with @XApiIgnore Annotation Use the `@XApiIgnore` annotation to exclude entire controllers or specific endpoints from documentation generation. ```java // Exclude entire controller from documentation @XApiIgnore @RestController @RequestMapping("/internal") public class InternalController { @GetMapping("/health") public String health() { return "OK"; } @GetMapping("/metrics") public MetricsDto metrics() { return metricsService.collect(); } } // Exclude specific methods from a documented controller @RestController @RequestMapping("/api/users") public class UserController { @GetMapping(name = "Get User", value = "/{id}") public UserDto getUser(@PathVariable Long id) { return userService.findById(id); } // This endpoint will not appear in documentation @XApiIgnore @GetMapping(name = "Debug Info", value = "/debug") public String debug() { return "debug information"; } // This endpoint will not appear in documentation @XApiIgnore @PostMapping(name = "Test Data", value = "/test-data") public void createTestData() { testDataService.create(); } } ``` ## API Exclusion via DSL Configuration Exclude packages or controller classes from documentation generation using DSL properties without modifying source code. ```groovy restMetaGenerator { documentPath = 'build/docs' basePackage = 'com.example' serviceId = 'my-service' // Exclude entire packages excludePackages = [ 'com.example.internal', 'com.example.admin', 'com.example.debug' ] // Exclude specific controller classes (simple names) excludeClasses = [ 'HealthCheckController', 'ActuatorController', 'SwaggerController' ] debug = false } ``` ## Pagination Support The plugin automatically recognizes Spring Data's `Pageable` parameter and `Page` return types, generating appropriate query parameters and response models. ```java @RestController @RequestMapping("/api/users") public class UserController { /** * Get users with pagination * * @param pageable Pagination information * @return Paginated user list * @group User Management */ @GetMapping(name = "Get Users Paged", value = "/paged") public Page getUsersPaged(Pageable pageable) { return userRepository.findAll(pageable); } } // Auto-generated query parameters: // - page (integer, default: 0) // - size (integer, default: 20) // - sort (string, e.g., "name,asc") // Auto-generated response model includes: // - content: T[] // - totalElements: long // - totalPages: int // - size: int // - number: int // - numberOfElements: int // - first: boolean // - last: boolean // - empty: boolean // - sort: object // API JSON includes: { "isPaging": true, "pagingType": "spring" } ``` ## ApiResult Wrapper Unwrapping The plugin automatically unwraps `ApiResult` wrapper types for single items, lists, and paginated responses. ```java @RestController @RequestMapping("/api/users") public class UserController { // Single item → returnClass: "UserDto" @GetMapping(name = "Get User Wrapped", value = "/wrapped/{id}") public ApiResult getUser(@PathVariable Long id) { return ApiResult.success(userService.findById(id)); } // List → returnClass: "UserDto", isArrayReturn: true @GetMapping(name = "Get Users Wrapped", value = "/wrapped") public ApiResult> getUsers() { return ApiResult.success(userService.findAll()); } // Paginated → returnClass: "UserDto", isPaging: true, pagingType: "spring" @GetMapping(name = "Get Users Paged Wrapped", value = "/wrapped/paged") public ApiResult> getUsersPaged(Pageable pageable) { return ApiResult.success(userRepository.findAll(pageable)); } } // ApiResult wrapper class example: public class ApiResult { private boolean success; private T data; private String message; public static ApiResult success(T data) { ApiResult result = new ApiResult<>(); result.success = true; result.data = data; return result; } } ``` ## Complex Query Parameter Objects The plugin automatically expands complex query parameter objects into individual parameters without requiring `@RequestParam` annotations. ```java // Query parameter DTO public class UserSearchRequest { private String name; @NotNull private UserStatus status; // enum → generates dropdown with values private Long networkId; private boolean active; // primitive → required @Size(min = 1) private String keyword; // @Size(min=1) → required } public enum UserStatus { ACTIVE, SUSPENDED, DELETED } @RestController @RequestMapping("/api/users") public class UserController { /** * Search users with filters * * @param search Search criteria * @return Matching users */ @GetMapping(name = "Search Users", value = "/search") public List searchUsers(UserSearchRequest search) { return userService.search(search); } } // Generated OpenAPI query parameters: // - name: string, optional // - status: string, enum: [ACTIVE, SUSPENDED, DELETED], required (@NotNull) // - networkId: integer (int64), optional // - active: boolean, required (primitive) // - keyword: string, required (@Size min=1) ``` ## Running the Generator Execute the Gradle task to generate documentation. The task depends on `compileJava` and runs automatically after compilation. ```bash # Generate REST API documentation ./gradlew restMetaGenerator # Output directory structure: # build/docs/ # ├── {serviceId}.json # Service definition # ├── openapi.json # OpenAPI 3.0.3 specification # ├── spec-bundle.json # Unified bundle (service + APIs + models + errors) # ├── api/ # │ └── {ControllerName}.json # Per-controller API definitions # ├── model/ # │ └── {ClassName}.json # Per-model (DTO) definitions # └── error/ # ├── errors.json # Error code groups # └── error-response.json # Error response model structure # Example: View generated OpenAPI spec cat build/docs/openapi.json | jq '.paths' # Example: View generated spec bundle cat build/docs/spec-bundle.json | jq '.apis[0]' ``` ## Generated spec-bundle.json Structure The spec bundle combines all documentation into a single file for efficient loading by API documentation UIs. ```json { "service": { "serviceId": "my-service", "name": "My Service", "apiServerUrl": "https://api.example.com", "version": "v1.0", "introduction": "Service description from markdown file...", "auth": { "type": "apiKey", "headerKey": "Access-Token", "in": "header", "description": "Authentication description..." }, "headers": [ { "name": "X-Request-Id", "description": "Request tracking ID" } ] }, "apis": [ { "id": "getUser", "name": "Get User Details", "method": "GET", "urlMapping": "/api/users/{id}", "returnClass": "com.example.dto.UserDto", "parameters": [ { "name": "id", "type": "Long", "kind": "PATH", "required": true } ], "responseStatus": { "200": "Success", "404": "User not found" }, "errors": [ { "exception": "UserNotFoundException", "status": 404, "codes": [ { "code": "USER_001", "name": "USER_NOT_FOUND" } ] } ] } ], "models": { "com.example.dto.UserDto": { "name": "UserDto", "type": "Object", "fields": [ { "name": "id", "type": "Long" }, { "name": "name", "type": "String" }, { "name": "permissions", "type": "Set", "items": "String" } ] } }, "errors": [ { "group": "User Not Found", "exception": "UserNotFoundException", "status": 404, "codes": [ { "code": "USER_001", "name": "USER_NOT_FOUND", "message": "User not found" } ] } ], "errorResponse": { "name": "ApiErrorResponse", "type": "Object", "fields": [ { "name": "status", "type": "int" }, { "name": "code", "type": "String" }, { "name": "message", "type": "String" } ] } } ``` ## Full Configuration Example A comprehensive example showing all available configuration options for the plugin. ```groovy // build.gradle plugins { id 'java' id 'org.springframework.boot' version '3.2.0' id 'gradle-restdoc-generator' version '2.1.4' } repositories { mavenCentral() maven { url 'https://jitpack.io' } } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.data:spring-data-commons' implementation 'jakarta.validation:jakarta.validation-api' } restMetaGenerator { // Required documentPath = 'build/docs' basePackage = 'com.example.api,com.example.admin' // Multiple packages serviceId = 'my-service' debug = false // Service information serviceName = 'My Awesome API' apiServerUrl = 'https://api.example.com' serviceVersion = 'v2.0' introductionFile = 'docs/introduction.md' // Error handling errorCodeClass = 'com.example.exception.ErrorCode' errorResponseClass = 'com.example.dto.ApiErrorResponse' // Exclusions excludePackages = ['com.example.internal', 'com.example.debug'] excludeClasses = ['HealthCheckController', 'MetricsController'] // Authentication (Bearer JWT) auth { type = 'http' scheme = 'bearer' bearerFormat = 'JWT' value = '{{accessToken}}' descriptionFile = 'docs/auth.md' } // Common headers header('X-Request-Id', '', 'Unique request identifier') header('X-Tenant-Id', 'default', 'Multi-tenant identifier') header('Accept-Language', 'en-US', 'Preferred language') // Postman integration postmanApiKey = System.getenv('POSTMAN_API_KEY') ?: '' postmanWorkSpaceId = System.getenv('POSTMAN_WORKSPACE_ID') ?: '' // Postman environments environment('LOCAL') { variable('base_url', 'http://localhost:8080') variable('accessToken', 'local-dev-token') } environment('DEV') { variable('base_url', 'https://dev.api.example.com') variable('accessToken', '') } environment('STAGING') { variable('base_url', 'https://staging.api.example.com') variable('accessToken', '') } environment('PROD') { variable('base_url', 'https://api.example.com') variable('accessToken', '') } } // Run after build build.finalizedBy restMetaGenerator ``` ## Summary The gradle-restdoc-generator plugin streamlines REST API documentation for Spring Boot applications by automatically generating OpenAPI 3.0.3 specifications, JSON metadata, and Postman collections directly from your controller source code. It eliminates manual documentation maintenance by leveraging Javadoc comments, validation annotations, and type information to produce comprehensive, accurate API documentation that stays synchronized with your codebase. Key integration patterns include using Javadoc tags for rich endpoint documentation, defining error codes in exception classes for automatic error catalog generation, leveraging Spring Data's pagination abstractions for automatic parameter expansion, and configuring multiple Postman environments for seamless API testing across development stages. The plugin supports various authentication schemes (API Key, Bearer, Basic), custom headers, and flexible exclusion mechanisms to tailor documentation output to your specific needs.