Skip to content

Clarify that API versioning for the client is not inferred from the server configuration #47373

@belyaev-andrey

Description

@belyaev-andrey

Assume that we have a versioned REST API:

@RestController
@RequestMapping("/api")
class QuoteController {

    @GetMapping(path = "/quote", produces = "application/json", version = "1.0+")
    ResponseEntity<Quote> getQuote() {
       //...
    }

    @GetMapping(path = "/quote", produces = "application/json", version = "2.0")
    ResponseEntity<List<Quote>> getQuotes() {
       //...
    }

It is configured like this:

spring:
  mvc:
    apiversion:
      use:
        header: API-Version

To test it properly, we need to invoke all endpoints with a proper version header:

        mockMvc.perform(get("/api/quote")
                        .accept(MediaType.APPLICATION_JSON)
                        .header("API-Version", "1.0")
                )
                .andExpect(status().isOk())

With Spring 7, we can use apiVersion method, which is more convenient and explicit

        mockMvc.perform(get("/api/quote")
                        .accept(MediaType.APPLICATION_JSON)
                        .apiVersion("1.0")
                )
                .andExpect(status().isOk())

The problem is that this approach doesn't work by default, error No ApiVersionInserter appears:

[ERROR] com.test.boot4.server.quote.QuoteControllerTest.getQuote_returnsJsonFromService -- Time elapsed: 0.025 s <<< ERROR!
java.lang.IllegalStateException: No ApiVersionInserter
        at org.springframework.util.Assert.state(Assert.java:80)
        at org.springframework.test.web.servlet.request.AbstractMockHttpServletRequestBuilder.buildRequest(AbstractMockHttpServletRequestBuilder.java:751)
        at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:170)

To fix this, we need to add a bit of boilerplate:

    @TestConfiguration
    static class QuoteControllerAddTestConfig implements MockMvcBuilderCustomizer {
        @Override
        public void customize(ConfigurableMockMvcBuilder<?> builder) {
            builder.apiVersionInserter(ApiVersionInserter.useHeader("API-Version"));
        }
    }

Suggestion:

Is it possible to perform this customization in a auto-configurer based on the application configuration? Basically, all the information we need is there, so why don't we reuse it?

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions