How to Migrate from Feign or OpenFeign to CoApi: A Step-by-Step Guide
To migrate from Feign or OpenFeign to CoApi, replace @FeignClient with @CoApi, swap @EnableFeignClients for @EnableCoApi, remove Feign dependencies, and let CoApi auto-configure Spring 6 WebClient or RestClient beans for reactive and synchronous HTTP calls.
CoApi is a zero-boilerplate replacement for Spring Cloud OpenFeign built on Spring 6's @HttpExchange. Unlike Feign, CoApi supports both reactive and synchronous programming models natively. This guide provides the exact steps to migrate your Spring Boot project using the ahoo-wang/coapi source code.
Step-by-Step Migration Process
1. Add the CoApi Starter Dependency
Include the CoApi Spring Boot starter in your build configuration. This brings in the auto-configuration that replaces Feign's @EnableFeignClients mechanism.
For Gradle:
implementation("me.ahoo.coapi:coapi-spring-boot-starter")
For Maven:
<dependency>
<groupId>me.ahoo.coapi</groupId>
<artifactId>coapi-spring-boot-starter</artifactId>
</dependency>
2. Remove Feign Dependencies
Delete all OpenFeign-related dependencies from your build file. Remove spring-cloud-starter-openfeign and any reactive Feign libraries like feign-reactive.
CoApi does not use Feign libraries; it uses Spring 6's WebClient under the hood for reactive streams and RestClient for blocking calls.
3. Replace @FeignClient with @CoApi
Convert your Feign client interfaces to CoApi by replacing the @FeignClient annotation with @CoApi. The annotation definition resides in [CoApi.kt](https://github.com/ahoo-wang/coapi/blob/main/api/src/main/kotlin/me/ahoo/coapi/api/CoApi.kt).
Before (Feign):
@FeignClient(name = "github", url = "\${github.url}")
interface GitHubFeignClient {
@GetMapping("repos/{owner}/{repo}/issues")
fun getIssues(@PathVariable owner: String, @PathVariable repo: String): List<Issue>
}
After (CoApi):
@CoApi(baseUrl = "\${github.url}")
interface GitHubApiClient {
@GetExchange("repos/{owner}/{repo}/issues")
fun getIssues(@PathVariable owner: String, @PathVariable repo: String): Flux<Issue>
}
The @CoApi annotation supplies the base URL, service ID, or load-balanced name and automatically registers the interface as a Spring bean.
4. Enable CoApi Scanning
Add @EnableCoApi to your @SpringBootApplication class or a configuration class, listing the client interfaces to register. The registrar logic is implemented in [EnableCoApiRegistrar.kt](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/EnableCoApiRegistrar.kt).
@EnableCoApi(clients = [GitHubApiClient::class])
@SpringBootApplication
class Application
The registrar discovers annotated interfaces and creates the necessary WebClient or RestClient bean definitions via [CoApiRegistrar.kt](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt).
5. Configure Load Balancing (Optional)
If you use service discovery, add spring-cloud-starter-loadbalancer and declare the client using serviceId or the lb:// protocol.
@CoApi(serviceId = "order-service")
interface OrderClient {
@GetExchange("/orders/{id}")
fun getOrder(@PathVariable id: Long): Mono<Order>
}
Alternatively, use baseUrl = "lb://my-service". CoApi detects the lb:// prefix in [CoApiDefinition.kt](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiDefinition.kt) and creates a load-balanced WebClient using Spring Cloud LoadBalancer.
6. Update Configuration Properties
Remove Feign-specific properties (e.g., feign.client.config.*) from your application.yml or application.properties. Replace them with standard Spring WebClient properties, or keep the same property names for base URLs.
github:
url: https://api.github.com
CoApi reads ${...} placeholders directly from the Spring Environment.
7. Remove @EnableFeignClients
Delete the @EnableFeignClients annotation from your main application class. This annotation is no longer needed because @EnableCoApi handles client registration.
8. Test the Migration
Run your integration tests to verify that CoApi beans are created correctly. The project includes tests such as [CoApiContextTest.kt](https://github.com/ahoo-wang/coapi/blob/main/spring/src/test/kotlin/me/ahoo/coapi/spring/CoApiContextTest.kt) that validate both reactive and synchronous bean creation.
@SpringBootTest
class CoApiContextTest {
@Autowired
lateinit var gitHubApiClient: GitHubApiClient
@Test
fun `should create Reactive CoApi bean`() {
assertNotNull(gitHubApiClient)
}
}
9. Clean Up
Remove any leftover Feign interfaces, configuration classes, and unused imports. Your project now relies solely on CoApi classes.
How CoApi Replaces Feign Internally
Understanding the internal mechanics ensures you can debug issues during migration.
Bean Registration: The CoApiDefinition class holds resolved client metadata including base URL, load-balancing flags, and bean names. The EnableCoApiRegistrar bridges the @EnableCoApi annotation with Spring's ImportBeanDefinitionRegistrar interface.
Reactive vs Synchronous: CoApi inspects return types to determine the client implementation. Interfaces returning Mono or Flux receive a reactive WebClient proxy. Interfaces returning concrete objects receive a synchronous RestClient proxy. This happens automatically in [CoApiRegistrar.kt](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt).
Zero Boilerplate: Unlike Feign, which requires explicit client builders or configuration classes, CoApi auto-registers clients based solely on the interface and annotation, eliminating manual @Bean definitions.
Summary
- Remove
spring-cloud-starter-openfeignand addcoapi-spring-boot-starter. - Replace
@FeignClientwith@CoApion your HTTP client interfaces. - Swap
@EnableFeignClientsfor@EnableCoApi(clients = [YourClient::class]). - Support both reactive (
WebClient) and synchronous (RestClient) patterns without extra configuration. - Enable load balancing using
serviceIdorlb://prefixes, resolved byCoApiDefinition.
Frequently Asked Questions
Do I need to change my interface method signatures when migrating to CoApi?
No, you only need to replace the annotation and import statements. Method signatures remain declarative, but you should update Spring MVC annotations (@GetMapping) to Spring 6 HTTP exchange annotations (@GetExchange). Return types determine whether CoApi uses WebClient (for Mono/Flux) or RestClient (for blocking types).
Can CoApi handle load-balanced clients like OpenFeign with Ribbon?
Yes, CoApi supports load balancing through Spring Cloud LoadBalancer. Specify serviceId = "my-service" or baseUrl = "lb://my-service" in the @CoApi annotation. The framework detects the lb:// protocol in CoApiDefinition and creates a load-balanced WebClient automatically.
Is reactive programming required when using CoApi?
No, CoApi supports both reactive and synchronous programming models. If your interface methods return Mono or Flux, CoApi configures a reactive WebClient. If they return concrete objects, it configures a synchronous RestClient. This dual support is a primary advantage over OpenFeign, which lacks native reactive capabilities.
What happens to my Feign fallback or error decoder implementations?
CoApi does not use Feign's ErrorDecoder or fallback mechanisms. You must implement error handling using Spring's WebClient filters or RestClient interceptors, or use standard Spring retry mechanisms. Remove any Feign-specific fallback classes and replace them with Spring-aware exception handling components.
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 →