Skip to content

Working with Spring Cloud OpenFeign

Somkiat Puisungnoen edited this page May 19, 2026 · 12 revisions

1. Add OpenFeign into project

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<dependency>
      <groupId>org.wiremock.integrations</groupId>
      <artifactId>wiremock-spring-boot</artifactId>
      <version>4.0.9</version>
</dependency>

2. Enable Feign Clients in Main class

@SpringBootApplication
@EnableFeignClients
public class Demoday1Application {

	public static void main(String[] args) {
...

3. Create Gateway interface to call External API

@FeignClient(value = "user-service", url = "${user.api.url}")
public interface UserGateway {

    @RequestMapping(method = RequestMethod.GET, value = "/users")
    List<User> getUsers();

    @RequestMapping(method = RequestMethod.GET, value = "/users/{userId}", produces = "application/json")
    User getUserById(@PathVariable("userId") Long postId);

}

4. Create Testing with Wiremock

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@EnableWireMock({
        @ConfigureWireMock(
                name = "my-mock",
                port = 8888)
})
class UserGatewayTest {

    @InjectWireMock("my-mock")
    WireMockServer mockUserService;

    @Test
    void getUserById() {
    }
}

5. Create stub and full testing

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.http.MediaType;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.util.ResourceUtils;
import org.wiremock.spring.ConfigureWireMock;
import org.wiremock.spring.EnableWireMock;
import org.wiremock.spring.InjectWireMock;

import java.io.File;
import java.nio.file.Files;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@EnableWireMock({@ConfigureWireMock(name = "my-mock", port = 8888)})
class UserGatewayTest {

    @InjectWireMock("my-mock")
    WireMockServer mockUserService;

    @Autowired
    UserGateway userGateway;

    // Dynamically set the Feign URL to point to the local WireMock instance
    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("user.api.url", () -> "http://localhost:8888");
    }

    public static String read(String filePath) throws Exception {
        File file = ResourceUtils.getFile(filePath);
        return new String(Files.readAllBytes(file.toPath()));
    }

    @Test
    void getUserById() throws Exception {
        // Arrange
        mockUserService.stubFor(get(urlPathEqualTo("/users/1")).willReturn(aResponse().withBody(read("classpath:userApiResponse.json")).withHeader(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).withStatus(200)));
        // Act
        UserResponse result = userGateway.getUserById(1L);
        // Assert
        assertEquals("demo", result.getUsername());
    }
}

6. Case :: 404

@Test
@DisplayName("Failure case with 404")
void case02() throws Exception {
    // Arrange
    mockUserService.stubFor(get(urlPathEqualTo("/users/1"))
            .willReturn(aResponse()
                    .withBody(read("classpath:userApiResponse404.json"))
                    .withHeader(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                    .withStatus(404)));
    // Act
    FeignException exception = assertThrows(FeignException.class, () -> {
        userGateway.getUserById(1L);
    });
    // Assert
    assertEquals(404, exception.status());
    assertEquals("""
            {
              "message": "User not found in system"
            }""", exception.contentUTF8());
}

7. Test case :: Timeout

Config application.properties

  • Defaults: Standard OpenFeign defaults are generally 10 seconds for connection and 60 seconds for reading
# Timeouts in milliseconds
spring.cloud.openfeign.client.config.default.connect-timeout=2000
spring.cloud.openfeign.client.config.default.read-timeout=2000

Write test case

@DisplayName("Slow response")
void case03() throws Exception {
    // Arrange
    mockUserService.stubFor(get(urlPathEqualTo("/users/1"))
            .willReturn(aResponse()
                    .withHeader(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                    .withFixedDelay(5000)
                    .withStatus(200)));
    // Act
    RetryableException exception = assertThrows(RetryableException.class, () -> {
        userGateway.getUserById(1L);
    });
    // Assert
    assertEquals("Read timed out executing GET http://localhost:8888/users/1", exception.getMessage());
}

Clone this wiki locally