Spring-hateoas: Add capabilities for prefixing WebMvcLinkBuilder?

Created on 14 Mar 2020  路  6Comments  路  Source: spring-projects/spring-hateoas

Please see https://stackoverflow.com/q/60680748/330457.

I'm trying to make my controllers prefixed with, say, /api/v1.

And it seems WebMvcLinkBuilder#linkTo(Class<?>) method is not aware of PathMatchConfigurer#addPathPrefix(String, Predicate<Class<?>>).

Can anybody please add some capability of adding prefixes to WebMvcLinkBuilder?

WebMvcLinkBuilder
//        .prefix("api")
//        .prefix("v1")
//        .prefixes("api", "v1")
//        .linkTo(controller)
//        .linkTo(controller, "api", "v1")
        .linkTo(controller)
        .withPrefixes("api", "v1")
;

Or do I have already an intrinsic way to do this?

bug webmvc core

All 6 comments

Can you paste an example controller into this ticket that you'd like to handle, so there's no confusion between a meandering SO question and a desired feature?

Thanks.

Hi, wondering if you found a workaround, I have the same issue and stumbled on this post...

I wrote this test case and verified this is a problem.

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration
class WebMvcConfigurerUnitTest {

    @Autowired WebApplicationContext context;

    MockMvc mockMvc;

    @BeforeEach
    void setUp() {
        this.mockMvc = webAppContextSetup(this.context).build();
    }

    @Test
    void customWebMvcConfigurerShouldWork() throws Exception {

        this.mockMvc.perform(get("/api").accept(MediaTypes.HAL_JSON)) //
                .andDo(print()) //
                .andExpect(status().isOk()) //
                .andExpect(jsonPath("$._links.self.href", is("http://localhost/api")));
    }

    @RestController
    static class TestController {

        @GetMapping
        RepresentationModel<?> root() {
            return new RepresentationModel<>(linkTo(methodOn(TestController.class).root()).withSelfRel());
        }

    }

    @Configuration
    @EnableWebMvc
    @EnableHypermediaSupport(type = HypermediaType.HAL)
    static class TestConfig {

        @Bean
        TestController controller() {
            return new TestController();
        }

        @Bean
        WebMvcConfigurer configureCustomPathPrefix() {

            return new WebMvcConfigurer() {

                @Override
                public void configurePathMatch(PathMatchConfigurer configurer1) {
                    configurer1.addPathPrefix("/api", HandlerTypePredicate.forAnyHandlerType());
                }
            };
        }

    }

}

The issue appears to be in here => https://github.com/spring-projects/spring-hateoas/blob/0d25b2e66e3800969ecb07c773d936ee3e6f0b69/src/main/java/org/springframework/hateoas/server/mvc/UriComponentsBuilderFactory.java#L47-L58

This is where Spring HATEOAS has access to the current servlet context. In the debugger I can see the /api as another attribute.

Simply put, we don't access it and apply it to the newly built URI.

I've traveled quite a ways down this rabbit hole, and I'm not sure the answer is feasible.

I tried to switch from "servlet mapping" to "current request" details deep inside link building, because my simple test case above happily turned green when you do that. This required that I reimplement "building a link outside a web call".

I made much progress down that path, but ran into what may be a fatal issue, one of our integration test cases.

If you are in the middle of a single-item method /employees/0, and trying to build a link to an aggregate root (/employees), then you run into issues.

Essentially, you either need the base URI (http://localhost:8080) + the target mapping (/employees based on annotations), which is what the project currently does.

Or you need the ability to look at the whole request (http://localhost:8080/employees/0) and know how to strip off what is ONLY covered in annotations, and THEN apply the NEW mapping.

So far, it appears that Spring MVC does not have a special designation for "prefixing" things. It basically uses what you provide (annotations, WebMvcConfigurer details) and builds up a the route for a method.

Configuring path prefixes and then later inspecting them to insert into the middle of a URI doesn't appear to be a primary use case built into Spring MVC.

Simply put, we may need to provide a configuration API to set a prefix (like /api), register our own WebMvcConfigurer, and then leverage that when building links.

This is very similar to what Spring Data REST currently does.

Perhaps it would be possible to pull that feature from SDR into Spring HATEOAS, and then update SDR to use it from Spring HATEOAS.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Doogiemuc picture Doogiemuc  路  8Comments

srinireddya picture srinireddya  路  3Comments

reda-alaoui picture reda-alaoui  路  7Comments

jbcpollak picture jbcpollak  路  8Comments

odrotbohm picture odrotbohm  路  6Comments