# How CoApi Interceptors Work: Modify Requests and Responses in Spring Boot

> Learn how CoApi interceptors modify Spring Boot requests and responses. Implement ClientHttpRequestInterceptor and configure via YAML for seamless integration.

- Repository: [Ahoo Wang/coapi](https://github.com/ahoo-wang/coapi)
- Tags: how-to-guide
- Published: 2026-02-23

---

**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`](https://github.com/ahoo-wang/coapi/blob/main//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`](https://github.com/ahoo-wang/coapi/blob/main//spring/src/main/kotlin/me/ahoo/coapi/spring/client/sync/AbstractRestClientFactoryBean.kt):

```kotlin
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`](https://github.com/ahoo-wang/coapi/blob/main/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:

```kotlin
@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`](https://github.com/ahoo-wang/coapi/blob/main/application.yml) using the `coapi.clients.{clientName}.sync.interceptor` namespace. You can reference beans by name or by fully-qualified class name:

```yaml
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`](https://github.com/ahoo-wang/coapi/blob/main//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`](https://github.com/ahoo-wang/coapi/blob/main/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.

```kotlin
@Service
class GitHubService(val gitHubApiClient: GitHubApiClient) {
    fun listRepos() = gitHubApiClient.repos().list()
}

```

## Summary

- CoApi interceptors implement Spring's `ClientHttpRequestInterceptor` interface for seamless integration with `RestClient`.
- Configuration uses `ClientProperties.InterceptorDefinition` with separate `names` and `types` lists to reference existing beans or instantiate new classes.
- The `AbstractRestClientFactoryBean` automatically wires interceptors into the client builder at lines 37-41 of its source file.
- Interceptors execute sequentially in declaration order: first `names`, then `types`.
- All configuration maps to YAML under `coapi.clients.{name}.sync.interceptor`, parsed by `CoApiProperties`.

## 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`](https://github.com/ahoo-wang/coapi/blob/main/CoApiProperties.kt) at lines 48-64. Unit tests verifying this mapping, including interceptor configuration, are located in [`CoApiPropertiesTest.kt`](https://github.com/ahoo-wang/coapi/blob/main/CoApiPropertiesTest.kt) at lines 112-114 according to the `ahoo-wang/coapi` source.