How CoApi Interceptors Work: Modify Requests and Responses in Spring Boot
CoApi interceptors let you modify HTTP requests and responses by implementing Spring's ClientHttpRequestInterceptor interface and registering your beans via YAML configuration, with the framework automatically wiring them into the synchronous RestClient built for each CoApi client.
CoApi interceptors provide a simple, extensible mechanism to plug custom request/response processing into your Spring-based API clients. In the ahoo-wang/coapi repository, this mechanism leverages Spring's RestClient builder to seamlessly integrate standard ClientHttpRequestInterceptor implementations. Whether you need to add authentication headers, log traffic, or transform payloads, interceptors give you fine-grained control over the HTTP lifecycle.
Understanding the CoApi Interceptor Architecture
Configuration Model
The interceptor configuration is defined in ClientProperties.InterceptorDefinition, which maintains two distinct lists for registration. The names list contains bean names of interceptors already registered in the Spring context, while the types list holds concrete classes that Spring can instantiate directly.
You access these definitions through the ClientProperties#getInterceptor(coApiName) method, located in /spring/src/main/kotlin/me/ahoo/coapi/spring/client/ClientProperties.kt at lines 31-34. This method retrieves the specific interceptor configuration bound to your named CoApi client.
Binding to the RestClient Builder
When CoApi constructs a synchronous client, AbstractRestClientFactoryBean retrieves the interceptor definition for the current CoApi (definition.name) and registers the interceptors with the RestClient builder. This happens at lines 37-41 of /spring/src/main/kotlin/me/ahoo/coapi/spring/client/sync/AbstractRestClientFactoryBean.kt:
val interceptorDefinition = clientProperties.getInterceptor(definition.name)
clientBuilder.requestInterceptors {
interceptorDefinition.initInterceptors(it)
}
Initialization and Execution Order
The extension function ClientProperties.InterceptorDefinition.initInterceptors, found at lines 50-60 of AbstractRestClientFactoryBean.kt, resolves each bean name or class from the application context and adds the resulting ClientHttpRequestInterceptor to the mutable list supplied by the builder.
Interceptors execute in the order they appear in configuration: first all entries in the names list, followed by all entries in the types list. The RestClient invokes them sequentially, allowing each interceptor to inspect or modify the outgoing HttpRequest and the incoming ClientHttpResponse.
Implementing a Custom CoApi Interceptor
Because interceptors implement Spring's standard ClientHttpRequestInterceptor interface, you can modify request headers, log payloads, apply authentication, or rewrite response bodies. Here is a complete example that adds a custom header to every request:
@Component
class HeaderAddingInterceptor : ClientHttpRequestInterceptor {
override fun intercept(
request: HttpRequest,
body: ByteArray,
execution: ClientHttpRequestExecution
): ClientHttpResponse {
val modified = request.headers.apply {
add("X-Custom-Header", "value")
}
return execution.execute(request, body)
}
}
Configuring Interceptors for Your CoApi Client
Register your interceptor via application.yml using the coapi.clients.{clientName}.sync.interceptor namespace. You can reference beans by name or by fully-qualified class name:
coapi:
clients:
GitHubApiClient:
sync:
interceptor:
names: [ headerAddingInterceptor ] # bean name (lower‑camel case)
# or alternatively:
# types: [ com.example.HeaderAddingInterceptor ]
The configuration binding logic resides in /spring-boot-starter/src/main/kotlin/me/ahoo/coapi/spring/boot/starter/CoApiProperties.kt at lines 48-64, with validation tests available in CoApiPropertiesTest.kt at lines 112-114.
Request Lifecycle and Execution Flow
When you invoke a method on your CoApi client, the request flows through the interceptor chain before reaching the target API:
GitHubService -> RestClient (built by AbstractRestClientFactoryBean)
→ requestInterceptors (HeaderAddingInterceptor)
→ HTTP request sent to GitHub API
Any request sent through GitHubApiClient will now contain the "X-Custom-Header" injected by your interceptor.
Advanced Configuration Patterns
Because interceptors are standard Spring beans, you can leverage the full Spring ecosystem for advanced use cases. Use @ConditionalOnProperty or profile-based configuration to conditionally register interceptors for specific environments. You can also replace implementations at runtime by overriding bean definitions in test configurations or using @Primary annotations.
@Service
class GitHubService(val gitHubApiClient: GitHubApiClient) {
fun listRepos() = gitHubApiClient.repos().list()
}
Summary
- CoApi interceptors implement Spring's
ClientHttpRequestInterceptorinterface for seamless integration withRestClient. - Configuration uses
ClientProperties.InterceptorDefinitionwith separatenamesandtypeslists to reference existing beans or instantiate new classes. - The
AbstractRestClientFactoryBeanautomatically wires interceptors into the client builder at lines 37-41 of its source file. - Interceptors execute sequentially in declaration order: first
names, thentypes. - All configuration maps to YAML under
coapi.clients.{name}.sync.interceptor, parsed byCoApiProperties.
Frequently Asked Questions
What is the execution order of CoApi interceptors?
Interceptors execute strictly in the order they appear in your configuration. The framework processes all entries in the names list first, followed by all entries in the types list. This sequence determines the chain of responsibility for modifying requests and responses.
Can I modify the response body using CoApi interceptors?
Yes. Inside your intercept method, call execution.execute(request, body) to obtain the ClientHttpResponse, then wrap or transform the response body before returning it. The returned ClientHttpResponse propagates back through the interceptor chain to your service interface.
How do I disable an interceptor for a specific CoApi client?
Remove the interceptor's bean name from the names list or its class from the types list in your YAML configuration for that specific client. Because configuration is per-client under coapi.clients.{clientName}, other clients remain unaffected.
Where is the interceptor configuration validated in the source code?
The YAML configuration binding to ClientProperties objects occurs in CoApiProperties.kt at lines 48-64. Unit tests verifying this mapping, including interceptor configuration, are located in CoApiPropertiesTest.kt at lines 112-114 according to the ahoo-wang/coapi source.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →