Search code examples
spring-bootkotlinjacksonfeign

Using abstract requests with Feign


I'm trying to use an interface as the RequestBody in Feign, but Feign is creating an empty object as the request. Is this not possible or am I doing something wrong here? I could not find anything on that topic so far.

This is a simplified example of what I am trying to do (in reality there are 3 different kinds of requests)

interface BookingClient {
    @RequestLine("POST /booking")
    @Headers("Content-Type: application/json")
    fun createBooking(request: BookingRequest): BookingResponse
}

interface BookingRequest
data class NormalBooking(
    val product: String
): BookingRequest
data class DiscountedBooking(
    val product: String,
    val discountCode: String
): BookingRequest

// Client Configuration
val client = Feign.builder()
        .client(feign.okhttp.OkHttpClient())
        .errorDecoder(BadEntityErrorDecoder())
        .encoder(JacksonEncoder())
        .decoder(JacksonDecoder(listOf(KotlinModule(), JavaTimeModule())))
        .logger(feign.Logger.JavaLogger())
        .logLevel(feign.Logger.Level.FULL)
        .target(BookingClient::class.java, mockServer.getUrl())

If I now call createBooking() with either implementation, Feign always serializes

{}

instead of

{
    "product": "productA"
}

and

{
    "product": "productA",
    "discountCode": "discountCode"
}

Solution

  • The problem is parameter type, when we invoke Feign.target(...), Feign start to parse your BookingClient to a Http request template, and body type is BookingRequest, so Feign always serializes "{}"

    interface BookingClient {
        @RequestLine("POST /booking")
        @Headers("Content-Type: application/json")
        // BookingRequest should change to NormalBooking or DiscountedBooking
        fun createBooking(request: BookingRequest): BookingResponse
    }