Skip to content

What is CoApi?

Overview

CoApi exists because Spring 6 introduced the HTTP Interface (@HttpExchange) but left a critical gap: there is no auto-configuration. Developers must manually wire HttpServiceProxyFactory, choose between WebClient and RestClient, handle URL resolution, and manage bean lifecycles. Meanwhile, OpenFeign — the de facto standard for declarative HTTP clients in Spring Cloud — lacks reactive programming support. Its recommended alternative, feign-reactive, is unmaintained and incompatible with Spring Boot 3.2+.

CoApi fills this gap with annotation-driven, zero-boilerplate auto-configuration. Define an interface, annotate it with @CoApi, and CoApi automatically registers the HTTP client bean, the JDK proxy, and all supporting infrastructure. It supports both reactive (WebClient) and synchronous (RestClient) models with a single annotation, and integrates client-side load balancing via Spring Cloud LoadBalancer.

At a Glance

ComponentResponsibilityKey FileSource
@CoApiMarks interfaces as HTTP clients, provides baseUrl/serviceId/nameCoApi.ktCoApi.kt
@LoadBalancedMarks interface for client-side load balancingLoadBalanced.ktLoadBalanced.kt
CoApiDefinitionParsed metadata: name, apiType, baseUrl, loadBalancedCoApiDefinition.ktCoApiDefinition.kt
CoApiRegistrarRegisters WebClient/RestClient + proxy beans per interfaceCoApiRegistrar.ktCoApiRegistrar.kt
CoApiFactoryBeanCreates JDK proxy via HttpServiceProxyFactoryCoApiFactoryBean.ktCoApiFactoryBean.kt
CoApiAutoConfigurationBoot auto-configuration entry pointCoApiAutoConfiguration.ktCoApiAutoConfiguration.kt

Why CoApi?

The Spring ecosystem has three approaches to declarative HTTP clients. Here is how they compare:

FeatureCoApiSpring Cloud OpenFeignManual HTTP Interface
Auto-configurationZero configZero configManual setup per client
Reactive support (WebClient)Built-inNoneManual
Synchronous support (RestClient)Built-inBuilt-inManual
Load balancingBuilt-inBuilt-inManual
Spring Boot 4.x / Spring 7.xSupportedSupportedSupported
Annotation-driven@CoApi@FeignClient@HttpExchange only
Dual-mode switchingcoapi.mode propertyN/ACode change required

How It Works

mermaid
graph LR
    subgraph "1. Define"
        A["@CoApi Interface"]
    end
    subgraph "2. Discover"
        B[AutoCoApiRegistrar]
        C[EnableCoApiRegistrar]
    end
    subgraph "3. Register"
        D["WebClient / RestClient Bean"]
        E[Proxy Bean]
    end
    subgraph "4. Use"
        F["Inject & Call"]
    end

    A --> B
    A --> C
    B --> D
    B --> E
    C --> D
    C --> E
    D --> E
    E --> F

The Two-Bean-Per-Interface Pattern

CoApi registers two beans for every @CoApi-annotated interface:

mermaid
sequenceDiagram
    autonumber
    participant Registrar as CoApiRegistrar
    participant Registry as BeanDefinitionRegistry
    participant WCF as WebClientFactoryBean
    participant CFB as CoApiFactoryBean
    participant Proxy as JDK Proxy

    Registrar->>Registry: registerBeanDefinition(name + ".HttpClient", WebClientFactoryBean)
    Registrar->>Registry: registerBeanDefinition(name + ".CoApi", CoApiFactoryBean)
    Note over WCF: Creates WebClient instance
    Note over CFB: Creates interface proxy
    CFB->>WCF: get HttpClient bean
    CFB->>Proxy: HttpServiceProxyFactory.createClient(apiType)
    Proxy-->>CFB: Proxy implementing @CoApi interface
  1. HTTP Client Bean (name.HttpClient) — a WebClient or RestClient configured with base URL, filters/interceptors, and optional load balancing.
  2. Proxy Bean (name.CoApi) — a JDK dynamic proxy implementing the annotated interface, generated by Spring's HttpServiceProxyFactory.

Client Mode Inference

mermaid
flowchart TD
    A[Application Starts] --> B{"coapi.mode property?"}
    B -->|REACTIVE| C["WebClient + WebClientAdapter"]
    B -->|SYNC| D["RestClient + RestClientAdapter"]
    B -->|AUTO or unset| E{org.springframework.web.reactive.HandlerResult on classpath?}
    E -->|Yes| C
    E -->|No| D

Module Architecture

mermaid
graph BT
    subgraph "Library Modules"
        API["api<br>@CoApi, @LoadBalanced"]
        SPRING["spring<br>Registrar, FactoryBean, Client SPI"]
        STARTER["spring-boot-starter<br>Auto-configuration, Properties"]
    end
    subgraph "Support"
        BOM["bom<br>Bill of Materials"]
        DEPS["dependencies<br>Version management"]
    end
    subgraph "Examples"
        PROV["example-provider-*"]
        CONS["example-consumer-*"]
        SYNC["example-sync"]
    end

    SPRING --> API
    STARTER --> SPRING
    BOM --> API
    BOM --> SPRING
    BOM --> STARTER
    DEPS --> API
    DEPS --> SPRING
    PROV --> API
    CONS --> STARTER
    SYNC --> STARTER

Version Compatibility

CoApi VersionSpring BootSpring FrameworkJDK
1.x3.2.x6.x17+
2.x4.x7.x17+

Current version: 2.0.1 (gradle.properties:21)

Key Features

  • Zero-boilerplate — one annotation, full auto-configuration
  • Dual-mode — reactive (WebClient) or synchronous (RestClient) via property or classpath inference
  • Load balancing — integrated with Spring Cloud LoadBalancer
  • CustomizableWebClientBuilderCustomizer / RestClientBuilderCustomizer SPI for global and per-client customization
  • Authentication — built-in BearerTokenFilter with JWT-aware CachedExpirableTokenProvider
  • Filter/interceptor — per-client filter chains configurable via YAML properties

References

  1. CoApi Annotationapi/src/main/kotlin/me/ahoo/coapi/api/CoApi.kt
  2. CoApiDefinitionspring/src/main/kotlin/me/ahoo/coapi/spring/CoApiDefinition.kt
  3. CoApiRegistrarspring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt
  4. CoApiFactoryBeanspring/src/main/kotlin/me/ahoo/coapi/spring/CoApiFactoryBean.kt
  5. ClientModespring/src/main/kotlin/me/ahoo/coapi/spring/ClientMode.kt
  6. README.md — Project overview and usage examples