OpenAPI/Swagger với springdoc-openapi — auto-generate API doc
OpenAPI 3.x là chuẩn industry mô tả REST API. Bài này bóc springdoc-openapi (Boot 3 native), auto-detect controller annotation → spec, customize qua @Operation/@Schema, security scheme, group multi-API, và pattern API-first vs code-first.
REST API không có doc = không usable. Frontend không biết endpoint nào, field gì, status code nào. Trước 2014, doc viết tay trong Confluence — luôn outdated, sai khác code. OpenAPI Specification (trước: Swagger 2.0) ra đời 2014 chuẩn hoá: format JSON/YAML mô tả API + tool sinh client + UI test.
Bài này bóc springdoc-openapi — lib auto-generate OpenAPI spec từ Spring controller annotation. Đặt 1 dependency, get full doc UI tại /swagger-ui.html. Customize qua @Operation, @Schema, security scheme. Pattern thực tế cho TaskFlow capstone.
1. OpenAPI là gì
OpenAPI Specification (OAS) — chuẩn JSON/YAML mô tả REST API. Phiên bản hiện tại 3.1 (2021).
Example minimal spec:
openapi: 3.1.0
info:
title: Order API
version: 1.0.0
paths:
/orders/{id}:
get:
operationId: getOrder
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: Order found
content:
application/json:
schema:
$ref: '#/components/schemas/OrderDto'
'404':
description: Order not found
components:
schemas:
OrderDto:
type: object
properties:
id: { type: integer, format: int64 }
customer: { type: string }
total: { type: number }
Spec mô tả toàn bộ contract: endpoint, method, parameter, body, response status, schema.
1.1 Tool ecosystem
OpenAPI spec là fuel cho ecosystem tool:
| Tool | Use |
|---|---|
| Swagger UI | Render spec thành interactive HTML — try-it-out |
| OpenAPI Generator | Sinh client SDK 50+ ngôn ngữ (TypeScript, Python, Kotlin, ...) |
| Postman | Import spec → auto-create collection |
| Spectral | Lint spec — catch design issue |
| Stoplight Studio | Visual editor cho spec |
| API Mocking (Prism, Mockoon) | Run spec as mock server |
Lợi ích: API-first workflow — design spec trước, frontend + backend implement song song dựa vào spec. Không phải đợi backend xong mới dev frontend.
2. springdoc-openapi — Boot 3 native
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version>
</dependency>
Add 1 dependency, no config required. Boot autoconfig:
- Scan controller
@RestController+ annotation MVC. - Generate spec at
/v3/api-docs(JSON) and/v3/api-docs.yaml. - Render Swagger UI at
/swagger-ui.html.
Run app, mở browser http://localhost:8080/swagger-ui.html:
[Swagger UI]
├── Order API (1.0.0)
│ ├── GET /api/v1/orders List orders
│ │ ├── Parameters: page, size, status
│ │ └── Responses: 200, 400
│ ├── GET /api/v1/orders/{id} Get order by ID
│ ├── POST /api/v1/orders Create order
│ ├── PUT /api/v1/orders/{id} Update order
│ └── DELETE /api/v1/orders/{id} Delete order
└── Schemas
├── OrderRequest
├── OrderDto
└── ProblemDetail
Click endpoint → expand detail → "Try it out" → execute trực tiếp từ UI. Cực kỳ tiện debug + onboard dev mới.
2.1 Auto-detection
springdoc đọc:
- Controller:
@RestController,@RequestMapping,@GetMapping/@PostMapping/... - Parameter:
@PathVariable,@RequestParam,@RequestBody,@RequestHeader. - Validation:
@NotNull,@Size,@Min,@Max,@Pattern→ schema constraint. - Response: return type +
ResponseEntity<T>. - Status code:
@ResponseStatusannotation. - Exception:
@ControllerAdvice@ExceptionHandler→ error response examples.
Đa phần auto đủ — bạn không cần annotate gì thêm.
3. Customize spec — annotation
Khi auto không đủ, dùng OpenAPI annotation từ io.swagger.v3.oas.annotations:
3.1 @Operation — describe endpoint
@Operation(
summary = "Get order by ID",
description = "Retrieves order details by its unique ID. Returns 404 if order not found.",
tags = {"Orders"}
)
@GetMapping("/orders/{id}")
public OrderDto get(@PathVariable Long id) { ... }
summary xuất hiện trong UI list. description xuất hiện khi expand. tags group endpoint thành section trong UI.
3.2 @Parameter — describe parameter
@GetMapping("/orders")
public List<OrderDto> list(
@Parameter(description = "Filter by status", example = "ACTIVE")
@RequestParam(required = false) OrderStatus status,
@Parameter(description = "Page number (0-indexed)", example = "0")
@RequestParam(defaultValue = "0") int page,
@Parameter(description = "Page size (1-100)", example = "20")
@RequestParam(defaultValue = "20") int size
) { ... }
example show trong UI — user thấy ngay value valid.
3.3 @Schema — describe DTO
@Schema(description = "Order request payload")
public record OrderRequest(
@Schema(description = "Customer name", example = "Alice", minLength = 2, maxLength = 100)
@NotBlank
String customer,
@Schema(description = "Order total in VND", example = "99.99", minimum = "0.01")
@NotNull @Positive
BigDecimal total,
@Schema(description = "Delivery date (ISO format)", example = "2026-04-20")
@NotNull @Future
LocalDate deliveryDate,
@Schema(description = "Order items", minItems = 1, maxItems = 100)
@NotEmpty @Size(max = 100)
@Valid
List<OrderItem> items
) {}
example rất quan trọng — user copy trong UI làm starting point.
3.4 @ApiResponses — describe response codes
@Operation(summary = "Create order")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "Order created",
content = @Content(schema = @Schema(implementation = OrderDto.class))),
@ApiResponse(responseCode = "400", description = "Validation failed",
content = @Content(schema = @Schema(implementation = ProblemDetail.class))),
@ApiResponse(responseCode = "409", description = "Duplicate order"),
@ApiResponse(responseCode = "500", description = "Internal error")
})
@PostMapping("/orders")
public ResponseEntity<OrderDto> create(@Valid @RequestBody OrderRequest req) { ... }
springdoc auto-detect 200/400 từ @RestControllerAdvice — nhưng explicit @ApiResponses cho documentation control.
4. OpenAPI metadata global
Customize info, server, contact:
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("OLHub TaskFlow API")
.version("v1.0")
.description("REST API for TaskFlow project management")
.contact(new Contact()
.name("OLHub Engineering")
.email("[email protected]")
.url("https://docs.olhub.org"))
.license(new License().name("Apache 2.0").url("https://www.apache.org/licenses/LICENSE-2.0")))
.servers(List.of(
new Server().url("https://api.olhub.org").description("Production"),
new Server().url("https://staging.olhub.org").description("Staging"),
new Server().url("http://localhost:8080").description("Local dev")
))
.externalDocs(new ExternalDocumentation()
.description("Full API documentation")
.url("https://docs.olhub.org"));
}
}
Hoặc qua property:
springdoc:
api-docs:
path: /v3/api-docs
enabled: true
swagger-ui:
path: /swagger-ui.html
operationsSorter: method
tagsSorter: alpha
tryItOutEnabled: true
filter: true
deepLinking: true
show-actuator: false # exclude actuator endpoints from docs
packages-to-scan: com.olhub.api # chi scan package nay
paths-to-match: /api/** # chi match URL pattern
5. Security scheme
App có JWT auth — UI cần "Authorize" button để inject token:
@Configuration
@SecurityScheme(
name = "bearerAuth",
type = SecuritySchemeType.HTTP,
scheme = "bearer",
bearerFormat = "JWT",
in = SecuritySchemeIn.HEADER
)
public class OpenApiConfig {
// ...
}
// Apply per controller
@SecurityRequirement(name = "bearerAuth")
@RestController
@RequestMapping("/api/orders")
public class OrderController { ... }
// Hoac global
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
.components(new Components()
.addSecuritySchemes("bearerAuth",
new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")));
}
UI hiện "Authorize" button. User paste JWT token → mọi request "Try it out" tự include Authorization: Bearer <token> header.
OAuth2 / OIDC scheme tương tự:
@SecurityScheme(
name = "oauth2",
type = SecuritySchemeType.OAUTH2,
flows = @OAuthFlows(
authorizationCode = @OAuthFlow(
authorizationUrl = "https://auth.olhub.org/oauth2/authorize",
tokenUrl = "https://auth.olhub.org/oauth2/token",
scopes = {
@OAuthScope(name = "read", description = "Read access"),
@OAuthScope(name = "write", description = "Write access")
}
)
)
)
6. Group multiple API
Big app có nhiều API context — public, admin, internal — group spec:
@Configuration
public class GroupedOpenApiConfig {
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("public")
.pathsToMatch("/api/v1/**")
.build();
}
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.group("admin")
.pathsToMatch("/api/admin/**")
.build();
}
@Bean
public GroupedOpenApi internalApi() {
return GroupedOpenApi.builder()
.group("internal")
.pathsToMatch("/internal/**")
.build();
}
}
Swagger UI có dropdown "Select Group" — chọn public / admin / internal. Mỗi group có spec riêng tại /v3/api-docs/\{group\}.
Pattern thực tế: public API doc public, admin/internal API restrict access.
7. Hide internal endpoint
Mặc định mọi endpoint expose trong spec. Hide:
// Method-level
@Hidden
@GetMapping("/internal/admin")
public ... internal() { ... }
// Class-level
@Hidden
@RestController
public class InternalController { ... }
Hoặc qua config:
springdoc:
packages-to-exclude: com.olhub.internal
paths-to-exclude: /internal/**
Hide actuator endpoints (default Boot 3+ already hidden):
springdoc:
show-actuator: false
8. Production deploy considerations
8.1 Disable trong production?
3 phương án:
Option 1 — Always enabled, public:
Pros: dev/QA test prod easily. Cons: expose API surface to attacker — discoverability.
Option 2 — Disable trong production:
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
Profile-specific:
# application-prod.yml
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
# application-dev.yml
springdoc:
api-docs:
enabled: true
Option 3 — Enabled but auth-protected:
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html")
.hasRole("ADMIN")
.anyRequest().authenticated()
);
return http.build();
}
}
Recommend Option 2 hoặc 3 cho production. Public API docs site (host trên CDN/separate site) cho external developer — không expose qua app server.
8.2 Versioning OpenAPI spec
Source of truth: OpenAPI spec generated từ controller — version theo Boot release. Lưu spec snapshot mỗi release:
# CI/CD pipeline
curl http://localhost:8080/v3/api-docs > openapi-v1.2.3.yaml
git add docs/api/openapi-v1.2.3.yaml
git commit -m "Snapshot API spec for v1.2.3"
Track diff giữa version → detect breaking change. Tool openapi-diff so 2 spec.
9. API-first vs code-first
2 workflow:
9.1 Code-first (springdoc default)
Developer code @RestController
→ springdoc auto-generate spec
→ Frontend đọc spec, implement
Pros:
- Single source of truth (code).
- Refactor code → spec auto update.
- Quick start.
Cons:
- Frontend đợi backend code xong mới có spec.
- Spec design phụ thuộc code — không design contract trước.
Phù hợp: team nhỏ, app simple, backend lead workflow.
9.2 API-first
Designer write OpenAPI spec
→ Generator sinh interface Spring + DTO
→ Backend implement interface
→ Frontend đọc spec, implement song song
Tool: openapi-generator-maven-plugin:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.10.0</version>
<executions>
<execution>
<goals><goal>generate</goal></goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>com.olhub.api.generated</apiPackage>
<modelPackage>com.olhub.api.generated.model</modelPackage>
<configOptions>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
<useJakartaEe>true</useJakartaEe>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
openapi.yaml define contract. Plugin sinh OrdersApi interface — controller implement:
@RestController
public class OrderController implements OrdersApi {
@Override
public ResponseEntity<OrderDto> getOrder(Long id) {
return ResponseEntity.ok(orderService.findById(id));
}
}
Pros:
- Contract rõ ràng trước implement.
- Frontend + backend song song.
- Validate spec với linter (Spectral) — catch design issue.
Cons:
- Setup complex.
- Generator quirks (DTO không idiomatic Java).
- Spec phải thiết kế kỹ — dễ overspec.
Phù hợp: team lớn, API public exposed, contract critical.
Khoá này (TaskFlow): code-first đơn giản. API-first introduced ở Module 11 (Microservices) khi cần.
10. Pitfall tổng hợp
❌ Nhầm 1: Tin springdoc auto-detect mọi thứ.
✅ Auto đủ ~80%. Custom với @Operation, @Schema, @ApiResponses cho clarity.
❌ Nhầm 2: Quên example trong @Schema.
✅ Add example — UI test "Try it out" tiện hơn 10x.
❌ Nhầm 3: Expose Swagger UI production public. ✅ Disable hoặc auth-protect. Doc public trên CDN/separate site.
❌ Nhầm 4: Spec version chỉ 1.0.
✅ Semver: v1.0.0, v1.1.0. Track breaking change qua minor/major bump.
❌ Nhầm 5: Quên security scheme cho JWT API.
✅ Add @SecurityScheme — UI có "Authorize" button, dev test endpoint protected dễ.
❌ Nhầm 6: Mix grouped API không filter. ✅ Group rõ ràng public/admin/internal — paths/packages explicit.
❌ Nhầm 7: OpenAPI spec không lint. ✅ Run Spectral CI: catch undocumented response, missing operationId, naming inconsistent.
11. 📚 Deep Dive Spring Reference
OpenAPI Specification:
- OpenAPI 3.1 Specification — chính chủ.
- OpenAPI Initiative — community + tooling.
springdoc-openapi:
- springdoc-openapi Reference — full docs.
- GitHub springdoc-openapi — source + examples.
- Spring Boot Migration to springdoc — migrate từ Springfox legacy.
Tooling:
- Swagger Editor — write/validate spec online.
- OpenAPI Generator — sinh client SDK 50+ ngôn ngữ.
- Spectral — lint spec.
- Stoplight Studio — visual editor.
Best practice:
- Microsoft REST API Guidelines
- Stripe API Docs — example design tốt.
- API-first development — Postman guide.
Tool:
- IntelliJ "Endpoints" tool window — visualize endpoints.
- Bruno / Postman — import spec → auto-create collection.
- redocly cli — render spec thành static HTML site.
12. Tóm tắt
- OpenAPI Specification 3.1 — chuẩn JSON/YAML mô tả REST API. Fuel cho ecosystem tool: Swagger UI, OpenAPI Generator, Postman, Spectral.
- springdoc-openapi 2.x — Boot 3 native, 1 dependency, auto-detect controller annotation → spec.
- Default endpoint:
/v3/api-docs(JSON),/v3/api-docs.yaml,/swagger-ui.html(UI). - Auto-detection đọc: controller annotation, parameter binding, validation constraint, return type, exception handler.
- Customize annotation từ
io.swagger.v3.oas.annotations:@Operation— describe endpoint (summary, description, tags).@Parameter— describe parameter (description, example).@Schema— describe DTO field (description, example, constraint).@ApiResponses— explicit response codes.
- OpenAPI metadata global qua
@Bean OpenAPI customOpenAPI()— info, server, contact, license. - Security scheme (
@SecurityScheme) cho JWT/OAuth2 — UI có "Authorize" button. - Grouped API (
GroupedOpenApi) — split public/admin/internal API thành group riêng. - Hide endpoint qua
@Hiddenhoặcspringdoc.paths-to-exclude. - Production deploy: disable hoặc auth-protect Swagger UI. Public docs via CDN/separate site.
- API-first vs code-first: code-first (springdoc default) cho team nhỏ. API-first (OpenAPI Generator) cho contract critical.
13. Tự kiểm tra
Q1Vì sao auto-generated OpenAPI spec từ springdoc thường đủ ~80% nhưng không 100%? Cho 3 ví dụ thông tin auto không capture.▸
Auto-detection lấy thông tin từ Java type system + Spring annotation:
- URL path → từ
@RequestMapping. - HTTP method → từ
@GetMapping/@PostMapping/... - Parameter type, optional → từ
@PathVariable/@RequestParam. - Schema field → từ DTO type (record component, class field).
- Constraint → từ
@NotNull/@Size/@Min/... - Response status → từ
@ResponseStatus,ResponseEntity.
3 ví dụ thông tin auto KHÔNG capture (cần manual annotation):
- Description / summary của endpoint: auto chỉ có method name. Ngữ nghĩa "Get order by ID — returns 404 if not found, includes customer details" → cần
@Operation(summary, description). - Example value cho parameter/field: Java type không có "example". Frontend dev đọc spec không biết format đúng.
@Schema(example = "ABC-1234") String sku; @Schema(example = "2026-04-15") LocalDate deliveryDate; @Parameter(example = "ACTIVE") OrderStatus status; - Business meaning của response code khác 200: auto detect
@ResponseStatus(NOT_FOUND)→ 404. Nhưng "404 = order ID không tồn tại" vs "404 = endpoint không exist" cùng status code — khác semantic.@ApiResponses({ @ApiResponse(responseCode = "200", description = "Order found"), @ApiResponse(responseCode = "404", description = "Order ID does not exist"), @ApiResponse(responseCode = "403", description = "Not authorized to view this order") })
Other thông tin manual:
- Tag grouping (organize endpoints).
- Security requirements per endpoint.
- Deprecation note (
@Deprecatedannotation work but description thiếu). - External documentation link.
- Custom schema constraint (regex pattern explanation, format like "ISO 8601 date").
Quy tắc: auto generate baseline. Bổ sung @Operation, @Schema(example), @ApiResponses cho 5-10 endpoint critical đầu tiên. Onboard dev mới đọc doc → chỉ ra chỗ nào unclear → bổ sung.
Q2Production app có Swagger UI exposed public — có nên không? Tradeoff?▸
Default: NO. Disable hoặc auth-protect production.
Lý do disable:
- API surface discoverability: attacker mở
/swagger-ui.html→ thấy mọi endpoint, parameter, schema. Tăng attack surface. - Validation rule leak: spec expose constraint (vd password "min 8 char + 1 uppercase") → dictionary attack design.
- Internal endpoint expose: dễ quên hide endpoint admin/debug → public discoverable.
- Performance: spec generation tốn CPU. Cron poll spec endpoint = wasted CPU.
- Trust: "Try it out" feature có thể attacker dùng probe production directly.
Lý do enable:
- Public API doc cho external developer (Stripe, GitHub style — họ host doc trên separate site, không expose qua app server).
- Internal team test prod nhanh.
- Auto-generated client SDK theo prod spec.
3 strategy:
- Disable hoàn toàn production:Doc generated từ staging snapshot, host trên CDN (vd
# application-prod.yml springdoc: api-docs: enabled: false swagger-ui: enabled: falsedocs.olhub.org) — separate domain, separate auth. - Auth-protect:Internal team có credential access.
@Bean public SecurityFilterChain filterChain(HttpSecurity http) { http.authorizeHttpRequests(auth -> auth .requestMatchers("/swagger-ui/**", "/v3/api-docs/**") .hasRole("DEVELOPER") .anyRequest().permitAll() ); return http.build(); } - Path obscurity (weakest):Security through obscurity — không recommended primary defense.
springdoc: swagger-ui: path: /admin/internal-docs-x7k9q # khó đoán URL api-docs: path: /admin/internal-spec-x7k9q
Recommend cho TaskFlow capstone:
- Dev/staging: Swagger UI enabled cho dev test.
- Production: disable. CI/CD snapshot spec từ staging → host trên
docs.olhub.org(Redocly hoặc Stoplight Elements).
Pattern này industry standard cho public API enterprise.
Q3Team backend + frontend cần work song song. Backend chưa code xong API. So sánh code-first (springdoc) vs API-first (OpenAPI Generator) cho scenario này.▸
Scenario: parallel development. API-first thắng rõ.
| Aspect | Code-first (springdoc) | API-first (OpenAPI Generator) |
|---|---|---|
| Khi nào có spec | Sau khi code Spring controller | Trước khi code (design phase) |
| Frontend đợi | ✅ phải đợi backend | ❌ song song với backend |
| Mock server | Khó — không có spec → không có mock | Easy — Prism/Mockoon đọc spec, sinh mock |
| Contract change | Backend đổi code → frontend phát hiện sau | Spec change → cả 2 team review trước |
| Contract drift | Code thay đổi spec auto follow | Generator regenerate interface → backend phải implement |
| Setup overhead | 1 dependency | OpenAPI Generator + define spec.yaml |
| Spec quality | Auto, có thể không idiomatic | Manual write — high quality, designed |
| Refactor cost | Refactor code, spec follow | Refactor spec, regenerate interface, fix backend |
Workflow API-first cho parallel team:
- Day 1: Tech lead viết
openapi.yaml(1 file, all endpoints + schema). Review với 2 team. - Day 2: Sign off spec.
- Backend:
openapi-generatorsinhOrdersApiinterface + DTO. Backend implement interface. - Frontend: chạy Prism mock
prism mock openapi.yaml --port 4010. Frontend dev với mock server.
- Backend:
- Day 3-5: Backend + frontend song song.
- Day 6: Frontend chuyển từ mock sang real backend. Đa phần work — vì cùng spec.
- Spec change mid-sprint: update
openapi.yaml, regenerate cả 2 side. Diff explicit.
Workflow code-first cho parallel team (workaround):
- Backend code controller skeleton trả mock data (return hardcoded DTO).
- springdoc generate spec từ skeleton.
- Frontend đọc spec, dev.
- Backend implement real logic — interface không đổi.
Workaround code-first work nhưng yếu hơn — backend phải prioritize code skeleton trước, contract không document explicit.
Recommend cho parallel team: API-first nếu team lớn (5+ dev), API exposed external. Code-first nếu nhỏ (1-3 dev), iteration nhanh.
Khoá này (TaskFlow): code-first đơn giản. Module 11 (Microservices) introduce API-first cho service contract giữa team.
Q4Implement security scheme cho app với JWT authentication. UI cần "Authorize" button.▸
Code đầy đủ:
@Configuration
@SecurityScheme(
name = "bearerAuth",
type = SecuritySchemeType.HTTP,
scheme = "bearer",
bearerFormat = "JWT",
in = SecuritySchemeIn.HEADER,
description = "JWT token from /auth/login endpoint"
)
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("TaskFlow API")
.version("v1.0"))
.addSecurityItem(new SecurityRequirement().addList("bearerAuth")); // global apply
}
}Apply security per controller (override global):
// Public endpoint - no auth required
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@SecurityRequirements // empty — override global, no auth
@PostMapping("/login")
public TokenDto login(@Valid @RequestBody LoginRequest req) { ... }
}
// Protected endpoint - bearerAuth required (inherit global, can be explicit)
@SecurityRequirement(name = "bearerAuth")
@RestController
@RequestMapping("/api/orders")
public class OrderController { ... }UI experience:
- Mở
/swagger-ui.html. - Top right: button "Authorize" (lock icon).
- Click → modal popup "Bearer authentication: enter JWT token".
- User paste token (vd
eyJhbGc...). - "Authorize" button.
- Mọi "Try it out" sau đó tự include header
Authorization: Bearer eyJhbGc....
Workflow dev:
- Login: POST
/api/auth/loginvới credential. Response trả JWT. - Copy JWT từ response.
- Click "Authorize" UI → paste JWT.
- Test mọi protected endpoint với "Try it out".
Tiện hơn 10x so với manual set header trong Postman.
OAuth2 với authorization code flow:
@SecurityScheme(
name = "oauth2",
type = SecuritySchemeType.OAUTH2,
flows = @OAuthFlows(
authorizationCode = @OAuthFlow(
authorizationUrl = "https://auth.olhub.org/oauth2/authorize",
tokenUrl = "https://auth.olhub.org/oauth2/token",
scopes = {
@OAuthScope(name = "read", description = "Read access"),
@OAuthScope(name = "write", description = "Write access")
}
)
)
)UI redirect user đến auth server, callback nhận code, exchange token. OAuth2 client ID/secret config trong UI.
Q5Big app có public API + admin API + internal API. Setup spec group ra sao? Lợi ích cho doc và security?▸
Setup grouped OpenAPI:
@Configuration
public class OpenApiConfig {
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("public")
.displayName("Public API (v1)")
.pathsToMatch("/api/v1/**")
.packagesToScan("com.olhub.api.public")
.build();
}
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.group("admin")
.displayName("Admin API")
.pathsToMatch("/api/admin/**")
.packagesToScan("com.olhub.api.admin")
.addOpenApiCustomizer(openApi -> openApi.info(
new Info().title("Admin API — INTERNAL").version("v1")
))
.build();
}
@Bean
public GroupedOpenApi internalApi() {
return GroupedOpenApi.builder()
.group("internal")
.displayName("Service-to-Service Internal")
.pathsToMatch("/internal/**")
.build();
}
}Swagger UI: dropdown top-right "Select Definition":
- Public API (v1) → endpoint
/api/v1/**. - Admin API → endpoint
/api/admin/**. - Service-to-Service Internal → endpoint
/internal/**.
Spec endpoints separate:
/v3/api-docs/public— public spec./v3/api-docs/admin— admin spec./v3/api-docs/internal— internal spec.
Lợi ích cho doc:
- Cleanly separated: public dev không thấy admin endpoint trong UI.
- Different titling/branding: public title "OLHub TaskFlow API", admin title "Admin Console (Internal Use)".
- Different versioning: public v1.0 stable contract, admin v1.5 evolve fast.
- Generate separate client SDK: public SDK ship cho external, admin SDK chỉ internal.
Lợi ích cho security:
- Selective exposure:UI production chỉ show public group. Admin + internal spec endpoint disabled hoặc auth-protected.
# application-prod.yml springdoc: show-actuator: false swagger-ui: disable-swagger-default-url: true urls: - name: Public API url: /v3/api-docs/public # Admin + internal NOT exposed in production UI - Auth-protect specific group:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) { http.authorizeHttpRequests(auth -> auth .requestMatchers("/v3/api-docs/admin", "/v3/api-docs/internal") .hasRole("ADMIN") .requestMatchers("/v3/api-docs/public").permitAll() ... ); } - CI/CD snapshot: snapshot riêng spec mỗi group → public spec ship cho external doc site, admin spec ship cho internal wiki.
Pattern enterprise tương tự: Stripe có 2 spec — public API + Connect API. Group cho phép modular API surface.
Bài tiếp theo: Mini-challenge — TaskFlow REST API v1 capstone
Bài này có giúp bạn hiểu bản chất không?
Bình luận (0)
Đang tải...