Careeroza
Documenting Endpoints
Annotations
Annotation (io.swagger.v3.oas.annotations) | Where | Purpose |
|---|---|---|
@Tag | controller class | Group name and description |
@Operation | method | Summary and description of the endpoint |
@ApiResponse | method | Possible status codes and their meaning |
@Parameter | parameter | Describe a path/query parameter |
@Schema | DTO / field | Field description and example value |
A Documented Controller
@Tag(name = "Products", description = "Browse and manage the product catalogue")
@RestController
@RequestMapping("/api/products")
class ProductController {
@Operation(summary = "Get one product", description = "Returns a product by its id.")
@ApiResponse(responseCode = "200", description = "Product found")
@ApiResponse(responseCode = "404", description = "No product with this id",
content = @Content(mediaType = "application/problem+json",
schema = @Schema(implementation = ProblemDetail.class)))
@GetMapping("/{id}")
ProductResponse get(@Parameter(description = "Product id", example = "1") @PathVariable Long id) {
return service.get(id);
}
}
public record CreateProductRequest(
@Schema(description = "Stock keeping unit", example = "ELE-1001") @NotNull @ValidSku String sku,
@Schema(example = "Wireless Mouse") @NotBlank @Size(max = 120) String name,
@Schema(example = "799.00") @NotNull @DecimalMin("0.01") BigDecimal price,
@Schema(example = "120") @PositiveOrZero int stock,
@Schema(example = "Electronics") @NotBlank String category) {}How springdoc Finds Your Endpoints
Example
springdoc scans controller methods and their annotations with reflection when the app starts. The same idea, in a few lines:
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.*;
public class Main {
public static void main(String[] args) {
Method[] methods = ProductController.class.getDeclaredMethods();
Arrays.sort(methods, Comparator.comparing(Method::getName));
System.out.println("paths:");
for (Method m : methods) {
Endpoint e = m.getAnnotation(Endpoint.class);
if (e == null) continue;
System.out.println(" " + e.method() + " " + e.path());
System.out.println(" summary: " + e.summary());
System.out.println(" operationId: " + m.getName());
}
}
}
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface Endpoint { String method(); String path(); String summary(); }
class ProductController {
@Endpoint(method = "GET", path = "/api/products", summary = "List products")
void list() {}
@Endpoint(method = "GET", path = "/api/products/{id}", summary = "Get one product")
void get() {}
@Endpoint(method = "POST", path = "/api/products", summary = "Create a product")
void create() {}
void helper() {} // not an endpoint: ignored
}Output
paths:
POST /api/products
summary: Create a product
operationId: create
GET /api/products/{id}
summary: Get one product
operationId: get
GET /api/products
summary: List products
operationId: list