Speakeasy Logo
Skip to Content

Spring Boot Integration for Java SDKs

Speakeasy auto-generates Spring Boot starters  alongside Java SDKs, enabling zero-configuration integration with sensible defaults.

Module Structure

  • build.gradle

Three modules provide complete Spring Boot integration:

Configuration Properties

Type-safe @ConfigurationProperties are auto-generated from your OpenAPI spec, namespaced under projectId:

@ConfigurationProperties(prefix = "my-api") // From your gen.yaml projectId public class MyApiProperties { // Core Configuration private String serverUrl; // From OpenAPI servers section private String server; // Server name (if using named servers) private int serverIdx = 0; // Server index (0-based, defaults to first server) // Server Variables (from OpenAPI spec) private ServerVariables serverVariables = new ServerVariables(); // Security Configuration (flattened from OpenAPI security schemes) private Security security = new Security(); // Global Parameters (from OpenAPI components) private Globals globals = new Globals(); // SDK Behavior Configuration private RetryConfig retryConfig = new RetryConfig(); private HttpClient httpClient = new HttpClient(); }

Property Mapping:

  • Servers: Indexed (serverIdx) or named (server) with variables as enums
  • Security: Flattened schemes (API keys, OAuth, HTTP auth)
  • Global Parameters: Headers, query params, path params from spec
  • SDK Behavior: Retry policies, HTTP client settings
  • Rich Types: OpenAPI enums → Java enums, duration strings → Duration objects

Auto-Configuration

Beans are conditionally registered based on classpath and properties:

@AutoConfiguration @ConditionalOnClass(SDK.class) @EnableConfigurationProperties(MyApiProperties.class) public class MyApiAutoConfiguration { @Bean @ConditionalOnMissingBean public SDK sdk(SDKConfiguration config) { return new SDK(config); // Main SDK bean } @Bean // Individual sub-SDKs automatically available @ConditionalOnMissingBean public UsersSDK usersSDK(SDK sdk) { return sdk.users(); } @Bean // Conditional on property presence @ConditionalOnProperty(prefix = "my-api.retry-config", name = "strategy") public RetryConfig retryConfig(MyApiProperties properties) { return convertToRetryConfig(properties.getRetryConfig()); } @Bean // Conditional on security configuration @ConditionalOnPropertyPrefix(prefix = "my-api.security") public SecuritySource securitySource(MyApiProperties properties) { return buildSecurityFromProperties(properties.getSecurity()); } }

Bean Registration:

  • Core SDK: Always present with starter
  • Sub-SDKs: Per API group (Users, Orders, etc.)
  • Security: Conditional on my-api.security.*
  • Retry: Conditional on my-api.retry-config.strategy
  • Async: When async mode enabled

Usage

Configure via application.yml:

my-api: # Namespace from your projectId server-url: "https://api.example.com" server-variables: # Rich type mapping with enum support environment: PROD # Enum values provide IDE dropdown selection region: US_EAST_1 # Type-safe enum prevents configuration errors security: # Structured security configuration api-key: "${API_KEY}" oauth: client-id: "${CLIENT_ID}" client-secret: "${CLIENT_SECRET}" retry-config: # SDK behaviors with readable duration formats strategy: BACKOFF # Enum with IDE autocomplete backoff: initial-interval: 500ms # Duration parsing: ms, s, m, h max-interval: 30s # Human-readable format max-elapsed-time: 5m # Automatically converted to Duration objects globals: # Global parameters from OpenAPI spec user-agent: "MyApp/1.0" api-version: "2023-10" http-client: # HTTP behavior configuration enable-debug-logging: false redacted-headers: ["Authorization", "X-API-Key"]

Inject and use with zero boilerplate:

@RestController public class UserController { @Autowired private UsersSDK usersSDK; // Direct sub-SDK injection @Autowired private AsyncUsersSDK asyncUsersSDK; // Async variant // Synchronous usage @GetMapping("/users/{id}") public User getUser(@PathVariable String id) { return usersSDK.getUser() .userId(id) .call(); } // Reactive usage with WebFlux @GetMapping("/users/{id}/async") public Mono<User> getUserAsync(@PathVariable String id) { return Mono.fromFuture( asyncUsersSDK.getUser() .userId(id) .call() // Returns CompletableFuture<User> ); } // Streaming data @GetMapping(value = "/users/stream", produces = "application/x-ndjson") public Flux<User> streamUsers(@RequestParam String department) { Publisher<User> userStream = asyncUsersSDK.listUsers() .department(department) .callAsPublisher(); // Returns Publisher<User> for pagination return Flux.from(userStream); } }

WebFlux Integration

Async SDKs integrate seamlessly with Spring WebFlux :

  • CompletableFutureMono conversion
  • PublisherFlux for streaming (pagination, SSE, JSONL)
  • Non-blocking reactive streams  support

Publishing

No workflow changes required. Gradle auto-configures additional artifacts:

  • {project-name}-spring-boot-autoconfigure-{version}.jar
  • {project-name}-spring-boot-starter-{version}.jar

Published alongside your main SDK to existing repositories.

Benefits

For API Producers:

  • Zero deployment overhead
  • Reduced support via familiar Spring Boot patterns 
  • Faster adoption by Spring developers
  • Enterprise appeal with Actuator  and ecosystem compatibility

For SDK Users:

  • Add starter dependency, configure via application.yml
  • Type-safe properties with IDE support
  • Rich type mapping (enums, durations)
  • WebFlux integration when async enabled

Compatibility: Spring Boot 2.x/3.x, Java 11+

Last updated on