简体   繁体   中英

Using WebClient in a controller tested with @WebFluxTests throws java.lang.IllegalArgumentException: URI is not absolute

I have a @RestController that uses WebClient in one of its endpoints to invoke another endpoint from the same controller:

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class FooRestController {

    private final WebClient webClient;

    @Value("${service.base-url}")
    private String fooServiceBaseUrl;

    @GetMapping(value = "/v1/foo", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Foo> getFoo() {
        return webClient.get().uri(fooServiceBaseUrl + "/api/v1/fooAnother")
                .retrieve()
                .bodyToFlux(Foo.class);
    }

    @GetMapping(value = "/v1/fooAnother", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Foo> getFooAnother() {
        return Flux.xxx
    }

In my @WebFluxTests class I can test the fooAnother endpoint without any problem:


@ExtendWith(SpringExtension.class)
@Import({MyWebClientAutoConfiguration.class})
@WebFluxTest(FooRestController.class)
class FooRestControllerTest {

    @Test
    void shouldGetFooAnother() {
        xxx
        webTestClient.get()
                .uri("/api/v1/fooAnother")
                .exchange()
                .expectStatus().isOk()
    }

    @Test
    void shouldGetFoo() {
        xxx
        webTestClient.get()
                .uri("/api/v1/fooAnother")
                .exchange()
                .expectStatus().isOk()
    }

However when I test the /v1/foo endpoint (notice in my tests service.base-url =""), it fails calling webClient.get().uri(fooServiceBaseUrl + "/api/v1/fooAnother") having fooServiceBaseUrl + "/api/v1/fooAnother" = "/api/v1/fooAnother" , complaining that it need an absolute URL: java.lang.IllegalArgumentException: URI is not absolute: /api/v1/fooAnother .

How could I fix this test?

You have to configure your WebClient using WebClient.Builder() . You could do this inside your FooRestController but I like to use Configuration that way if you have any further WebClient customizations, you could do in different class rather than in your controller class.

Configure WebClient:

@Configuration
public class WebClientConfig() {

    @Value("${service.base-url}")
    private String fooServiceBaseUrl;


    @Bean
    public WebClient webClient(WebClient.Builder builder) {
        return builder
            .baseUrl(fooServiceBaseUrl)
            .build();
    }
}

If you decide to go ahead with configuring your webClient in your FooRestController , you have to refactor as below. You don't need above configuration.

If this doesn't solve your issue, you might have some sort of mismatch between application.yml file and the value that your are trying to inject in fooServiceBaseUrl .


@RestController
@RequestMapping("/api")
public class FooRestController() {
    private final WebClient webClient;

    @Value("${service.base-url}")
    private String fooServiceBaseUrl;

    public FooRestController(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder
                .baseUrl(fooServiceBaseUrl)
                .build();   
    }

    @GetMapping(value = "/v1/foo", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Foo> getFoo() {
        return webClient
                .get()
                .uri("/api/v1/fooAnother")
                .retrieve()
                .bodyToFlux(Foo.class);
    }

    @GetMapping(value = "/v1/fooAnother", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Foo> getFooAnother() {
        return Flux.xxx
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM