How to Customize WebClient and RestClient Configurations in CoApi

You can customize CoApi's HTTP clients by setting coapi.* properties in your application.yml, providing your own WebClientCustomizer or RestTemplateCustomizer beans, or completely replacing the WebClient or RestTemplate beans with your own implementations.

CoApi is a declarative HTTP client framework for Spring Boot that auto-configures reactive WebClient and blocking RestTemplate instances. Understanding how to customize WebClient and RestClient configurations in CoApi allows you to tune timeouts, add interceptors, and swap underlying HTTP engines without modifying core library code.

Configuration Options Overview

CoApi exposes three distinct layers of customization:

  • Property-driven configuration – YAML/properties entries under the coapi prefix (e.g., coapi.webclient.connect-timeout).
  • Customizer beans – Spring beans implementing WebClientCustomizer or RestTemplateCustomizer that CoApi auto-detects and applies after its own defaults.
  • Full bean replacement – Declaring a @Primary (or named) WebClient or RestTemplate bean causes CoApi’s auto-configuration to back off entirely.

Property-Based Customization

The [CoApiProperties.kt](https://github.com/ahoo-wang/coapi/blob/main/spring-boot-starter/src/main/kotlin/me/ahoo/coapi/spring/boot/starter/CoApiProperties.kt) class maps external configuration to strongly-typed fields. You can set the following keys:

Property Type Description
coapi.webclient.connect-timeout Duration Connection timeout for the reactive client.
coapi.webclient.read-timeout Duration Response read timeout for the reactive client.
coapi.webclient.max-in-memory-size DataSize Maximum bytes buffered per response (prevents DataBufferLimitException).
coapi.restclient.connect-timeout Duration Connection timeout for the blocking client.
coapi.restclient.read-timeout Duration Response read timeout for the blocking client.

Example application.yml:

coapi:
  webclient:
    connect-timeout: 5s
    read-timeout: 30s
    max-in-memory-size: 10MB
  restclient:
    connect-timeout: 5s
    read-timeout: 30s

The [CoApiWebClientCustomizer.kt](https://github.com/ahoo-wang/coapi/blob/main/spring-boot-starter/src/main/kotlin/me/ahoo/coapi/spring/boot/starter/CoApiWebClientCustomizer.kt) and [CoApiRestTemplateCustomizer.kt](https://github.com/ahoo-wang/coapi/blob/main/spring-boot-starter/src/main/kotlin/me/ahoo/coapi/spring/boot/starter/CoApiRestTemplateCustomizer.kt) classes consume these properties and apply them to the underlying builders.

Programmatic Customization with Customizers

When YAML alone is insufficient, you can register Spring beans that implement WebClientCustomizer or RestTemplateCustomizer. CoApi’s auto-configuration detects these beans and invokes them after its own property-based customizer, giving you the final word on configuration.

Customizing the Reactive WebClient

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.WebClientCustomizer

@Configuration
class WebClientCustomization {

    @Bean
    fun loggingWebClientCustomizer(): WebClientCustomizer = WebClientCustomizer { builder ->
        builder
            .defaultHeader("X-Request-Source", "CoApi-Custom")
            .filter { request, next ->
                println(">> Sending ${request.method()} request to ${request.url()}")
                next.exchange(request)
            }
    }
}

Customizing the Blocking RestTemplate

import org.springframework.boot.web.client.RestTemplateCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.client.ClientHttpRequestInterceptor
import org.springframework.web.client.RestTemplate
import java.util.*

@Configuration
class RestTemplateCustomization {

    @Bean
    fun traceIdRestTemplateCustomizer(): RestTemplateCustomizer = RestTemplateCustomizer { template ->
        template.interceptors.add(ClientHttpRequestInterceptor { request, body, execution ->
            request.headers.add("X-Trace-Id", UUID.randomUUID().toString())
            execution.execute(request, body)
        })
    }
}

Because these beans are of type WebClientCustomizer and RestTemplateCustomizer, the [CoApiAutoConfiguration.kt](https://github.com/ahoo-wang/coapi/blob/main/spring-boot-starter/src/main/kotlin/me/ahoo/coapi/spring/boot/starter/CoApiAutoConfiguration.kt) automatically wires them into the client builders.

Complete Bean Replacement

If you need total control—such as swapping the underlying HTTP engine (e.g., OkHttp, Apache HttpClient 5) or applying global SSL settings—you can override the bean entirely.

Replacing the WebClient

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.web.reactive.function.client.WebClient
import reactor.netty.http.client.HttpClient
import java.time.Duration

@Configuration
class WebClientReplacement {

    @Bean
    @Primary
    fun coapiWebClient(): WebClient {
        val httpClient = HttpClient.create()
            .responseTimeout(Duration.ofSeconds(45))
            .compress(true)

        return WebClient.builder()
            .clientConnector(ReactorClientHttpConnector(httpClient))
            .defaultHeader("X-Custom-Engine", "Netty-Custom")
            .build()
    }
}

Replacing the RestTemplate

import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
import org.springframework.web.client.RestTemplate

@Configuration
class RestTemplateReplacement {

    @Bean
    @Primary
    fun coapiRestTemplate(): RestTemplate {
        val requestFactory = HttpComponentsClientHttpRequestFactory().apply {
            setConnectTimeout(2000)
            setReadTimeout(20000)
        }
        return RestTemplate(requestFactory)
    }
}

When a bean named coapiWebClient or coapiRestTemplate (or any @Primary bean of the respective type) exists, the @ConditionalOnMissingBean guards in CoApiAutoConfiguration.kt skip the auto‑configuration, ensuring your implementation is used throughout the application.

Summary

  • Property-driven: Set coapi.webclient.* and coapi.restclient.* in YAML to control timeouts and buffer sizes.
  • Customizer beans: Implement WebClientCustomizer or RestTemplateCustomizer to add headers, filters, or interceptors programmatically.
  • Full replacement: Declare a @Primary WebClient or RestTemplate bean to override the auto‑configured client entirely.

All three mechanisms are supported by the CoApiAutoConfiguration, CoApiProperties, CoApiWebClientCustomizer, and CoApiRestTemplateCustomizer classes in the CoApi Spring‑Boot starter.

Frequently Asked Questions

How do I change the connection timeout for CoApi WebClient?

Set the coapi.webclient.connect-timeout property in your application.yml (e.g., 5s). The CoApiWebClientCustomizer reads this value and applies it to the underlying HttpClient via the WebClient.Builder. If you need more granular control, provide a WebClientCustomizer bean and call builder.clientConnector() with a custom ReactorClientHttpConnector.

Can I use a custom HTTP client like OkHttp with CoApi?

Yes. Declare a @Primary WebClient bean that uses the OkHttpClient connector (via OkHttpClientConnector for WebClient) or a RestTemplate bean that uses OkHttp3ClientHttpRequestFactory. Because the bean is marked @Primary, CoApiAutoConfiguration will skip its own bean creation and use your custom implementation for all CoApi clients.

Why is my custom RestTemplate bean not being used by CoApi?

CoApi’s auto-configuration creates a RestTemplate bean only when no bean of that type exists (@ConditionalOnMissingBean). If your custom bean is not being picked up, ensure it is defined in a configuration class that is scanned by Spring Boot and that it is either named coapiRestTemplate or annotated with @Primary. Also verify that you are not accidentally creating the bean in a profile that is not active.

How do I add a logging interceptor to CoApi requests?

Provide a WebClientCustomizer (for reactive) or RestTemplateCustomizer (for blocking) bean. In the customizer, add a ExchangeFilterFunction to the WebClient.Builder (e.g., builder.filter(ExchangeFilterFunction.ofRequestProcessor { ... })) or add a ClientHttpRequestInterceptor to the RestTemplate. CoApi’s auto-configuration will detect these beans and apply them after the default property-based settings, ensuring your logging logic is active for all CoApi-generated clients.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →