π Step 2: Gateway Swagger Integration
π§ Series Navigation:
- βΆοΈ Spring Documentation Hub
- βΆοΈ Step 1: SpringDoc OpenAPI Integration
- β Step 2: Gateway Swagger Integration (Current)
- βΆοΈ Step 3: Advanced Swagger 3 Features
π₯ YouTube Video: Coming Soon – Subscribe to JavaiOS Channel
Swagger UI Integration via Spring Cloud Gateway π
This document explains how Swagger UI is aggregated across multiple microservices behind a Spring Cloud Gateway, detailing the request flow and how security is managed for a unified documentation experience.
In the AdventureTube microservice architecture, it requires a two-phase integration approach to properly aggregate documentation across all services while maintaining security and proper routing.
π§ Overview
Spring Cloud Gateway serves as the central entry point that aggregates Swagger documentation from multiple microservices into a single, unified interface. This approach provides developers with one place to discover, understand, and test all available APIs across the entire microservice ecosystem.
Key Benefits:
- Centralized Documentation – Single URL for all API documentation
- Unified Testing – Test APIs across different services from one interface
- Consistent Security – Standardized authentication across all documented endpoints
- Service Discovery – Automatic aggregation of new microservice documentation
π οΈ Two-Phase Integration Overview
πΉ Phase 1: Individual Service Configuration
Each microservice is configured with SpringDoc OpenAPI to generate Swagger documentation. These are then aggregated through the Gateway using predefined routes and exposed under a unified Swagger UI.
Reference: Complete Phase 1 implementation in Step 1
πΉ Phase 2: Gateway Security Configuration
After setting up the gateway forwarding, security configurations within each microservice must be adjusted to permit access to documentation endpoints (/v3/api-docs
, /swagger-ui/**
) while still protecting business logic routes with JWT-based filters.
π Complete Request Flow Analysis
1. Initial Swagger UI Request π―
A user accesses the Swagger UI at:
https://api.adventuretube.net/swagger-ui/index.html
This triggers SpringDoc in the gateway-service, using the following configuration:
springdoc:
swagger-ui:
enabled: true
path: /swagger-ui.html
urls:
- name: Auth Service
url: /auth-service/v3/api-docs
- name: Member Service
url: /member-service/v3/api-docs
- name: Web Service
url: /web-service/v3/api-docs
- name: Geospatial Service
url: /geo-service/v3/api-docs
api-docs:
enabled: true
These urls
define the destinations Swagger UI will call through the gateway to aggregate documentation from all microservices.
2. Gateway Routing and Security π
In GatewayConfig.java
, all primary API routes (e.g., /auth/**
, /member/**
, etc.) are configured with .filters(f -> f.filter(filter))
. This means every incoming request is:
- Intercepted by the global custom
AuthenticationFilter
- Forwarded to the appropriate microservice with the
/XXX-service
prefix stripped
Example: /auth-service/xyz
is forwarded as /xyz
to auth-service
π RouterValidator Configuration
The AuthenticationFilter
uses RouterValidator
to determine which endpoints should bypass authentication:
// Open endpoints that bypass JWT authentication
List.of(
"^/auth-service/v3/api-docs.*",
"^/member-service/v3/api-docs.*",
"^/web-service/v3/api-docs.*",
"^/geo-service/v3/api-docs.*",
"^/swagger-ui.*"
)
These paths are considered open endpoints, so while the filter still runs, it allows these requests through without token validation.
3. Route Forwarding Configuration π
Each Swagger documentation route uses .stripPrefix(1)
to clean up the path before forwarding:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// Swagger documentation routes
.route("auth-docs", r -> r.path("/auth-service/v3/api-docs")
.filters(f -> f.stripPrefix(1))
.uri("lb://auth-service"))
.route("member-docs", r -> r.path("/member-service/v3/api-docs")
.filters(f -> f.stripPrefix(1))
.uri("lb://member-service"))
.route("web-docs", r -> r.path("/web-service/v3/api-docs")
.filters(f -> f.stripPrefix(1))
.uri("lb://web-service"))
.route("geo-docs", r -> r.path("/geo-service/v3/api-docs")
.filters(f -> f.stripPrefix(1))
.uri("lb://geo-service"))
// Main API routes with authentication
.route("auth-service", r -> r.path("/auth-service/**")
.filters(f -> f.stripPrefix(1).filter(filter))
.uri("lb://auth-service"))
// Additional service routes...
.build();
}
Path Transformation:
- From:
/auth-service/v3/api-docs
- To:
/v3/api-docs
(inside the target microservice)
π§© Microservice Swagger Handling
π Auth Service Security Configuration
When the gateway forwards a request to /auth-service/v3/api-docs
, the route is stripped to /v3/api-docs
and passed to auth-service
.
- Spring Security Filter Chain Engagement: The request hits
auth-service
‘s Spring Security configuration:
@Bean
@Order(1)
public SecurityFilterChain apiFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf(AbstractHttpConfigurer::disable)
.securityMatcher("/auth/**")
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(
"/auth/register",
"/auth/login",
"/auth/refreshToken",
"/auth/logout",
"/swagger-ui.html",
"/swagger-ui/**",
"/v3/api-docs",
"/v3/api-docs/**"
).permitAll()
.anyRequest().hasRole("ADMIN")
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authenticationProvider(customAuthenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
Key Security Configurations:
- Open Documentation Endpoints:
/v3/api-docs
and/swagger-ui/**
are permitted without authentication - Protected Business Logic: All other
/auth/**
endpoints require ADMIN role - Stateless Session: No session state maintained for documentation requests
- JWT Filter Integration: Authentication filter runs but permits documentation access
π Complete Flow Diagram
User Request: https://api.adventuretube.net/swagger-ui/index.html
β
Gateway SpringDoc loads aggregated Swagger UI
β
Swagger UI requests: /auth-service/v3/api-docs
β
Gateway AuthenticationFilter (permits documentation endpoints)
β
Route forwarding: /auth-service/v3/api-docs β /v3/api-docs
β
Auth Service Spring Security (permits /v3/api-docs)
β
Auth Service SpringDoc generates OpenAPI specification
β
Response returns to Gateway β Swagger UI
β
User sees unified documentation interface
βοΈ Implementation Best Practices
1. Gateway Configuration
@Configuration
public class GatewayConfig {
@Autowired
private AuthenticationFilter filter;
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// Documentation routes (no authentication filter)
.route("auth-docs", r -> r.path("/auth-service/v3/api-docs")
.filters(f -> f.stripPrefix(1))
.uri("lb://auth-service"))
// API routes (with authentication filter)
.route("auth-service", r -> r.path("/auth-service/**")
.filters(f -> f.stripPrefix(1).filter(filter))
.uri("lb://auth-service"))
.build();
}
}
2. Service Discovery Integration
# Gateway application.yml
springdoc:
swagger-ui:
urls:
- name: Auth Service
url: /auth-service/v3/api-docs
- name: Member Service
url: /member-service/v3/api-docs
# Automatically discover services from Eureka
use-management-port: false
disable-swagger-default-url: true
3. CORS Configuration for Documentation
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/v3/api-docs/**", configuration);
source.registerCorsConfiguration("/swagger-ui/**", configuration);
return source;
}
π¨ Common Issues and Solutions
Issue 1: Internal URLs in Documentation
Problem: Swagger UI shows internal service URLs instead of gateway URLs
Solution: Add @OpenAPIDefinition
to each microservice:
@OpenAPIDefinition(
servers = {
@Server(url = "https://api.adventuretube.net", description = "AdventureTube API Gateway")
}
)
@SpringBootApplication
public class AuthServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AuthServiceApplication.class, args);
}
}
Issue 2: Authentication Errors for Documentation
Problem: Documentation endpoints require authentication
Solution: Ensure proper security configuration in each service:
// Add to security configuration
.requestMatchers(
"/v3/api-docs",
"/v3/api-docs/**",
"/swagger-ui.html",
"/swagger-ui/**"
).permitAll()
Issue 3: Gateway Route Conflicts
Problem: Documentation routes conflict with API routes
Solution: Order routes correctly – documentation routes before API routes:
return builder.routes()
// Documentation routes first (more specific)
.route("auth-docs", r -> r.path("/auth-service/v3/api-docs")...)
// API routes second (more general)
.route("auth-service", r -> r.path("/auth-service/**")...)
.build();
π Performance Considerations
Caching Strategy
# Enable caching for API docs
springdoc:
cache:
disabled: false
api-docs:
resolve-schema-properties: true
# Gateway-level caching
spring:
cloud:
gateway:
httpclient:
pool:
max-connections: 100
max-idle-time: 30s
Load Balancing for Documentation
// Custom load balancer configuration
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder()
.filter(ExchangeFilterFunction.ofRequestProcessor(
clientRequest -> {
// Add custom headers for documentation requests
if (clientRequest.url().getPath().contains("/v3/api-docs")) {
return Mono.just(ClientRequest.from(clientRequest)
.header("Cache-Control", "max-age=300")
.build());
}
return Mono.just(clientRequest);
}
));
}
β Implementation Checklist
Gateway Configuration β
- β SpringDoc aggregation configuration
- β Route definitions for documentation endpoints
- β Authentication filter bypass for docs
- β CORS configuration for cross-origin requests
Service Security β
- β Documentation endpoints permitted in security config
- β JWT filter integration maintained
- β Business logic endpoints protected
- β OpenAPI server URL configuration
Testing & Validation β
- β Unified Swagger UI accessible
- β All services documentation loading
- β Authentication working for protected endpoints
- β Documentation endpoints accessible without tokens
π Continue Your Documentation Journey
π§ Next Steps in Spring Documentation:
- βΆοΈ Spring Documentation Hub
- βΆοΈ Step 1: SpringDoc OpenAPI Integration
- β Step 2: Gateway Swagger Integration (Current)
- βΆοΈ Step 3: Advanced Swagger 3 Features
Part of the AdventureTube technical blog series supporting the JavaiOS YouTube channel.