18

I am using spring boot to write an api and I would like to map all my resources behind a common base path (/api in this case). However I don't want to annotate each RestController class to do this (by annotating it with @RequestMapping for example). I have thought about the following solutions but they all have a down side that i would rather not want:

  • Creating a base class (eg ApiRestController) and having all the other RestController inherit this one. This has as disadvantage that @Requestmapping on the class level isn't merged between the base and implementing classes.
  • Annotating all the RestController but this leads to code duplication
  • Changing the server.context-path property. This has as disadvantage that all endpoints will use this base path. Even the endpoints exposed by the actuator project.
  • Using a custom DispatcherServlet and ServletRegistrationBean. But this seems to have the same effect as changing the server.context-path.

So does anyone know how to do this without the disadvantages the solutions have that i summed. The project will only expose a REST-based backend and will not server any static content (don't know if this influences the possible solutions). The Restcontrollers are also divided over multiple packages.

Thanks.

Geert Olaerts
  • 1,155
  • 2
  • 9
  • 17
  • If I understood correctly, there is a Issue on Spring talking about this feature: https://jira.spring.io/browse/SPR-16336 – Dherik Feb 07 '18 at 17:32
  • The issue that @Dherik mentioned has been closed and I couldn't find out a solution. Did you find a way to resolve this? – Ramanujan R Jul 03 '21 at 14:06
  • For now I had to settle with this workaround, which places this specif path as a property in yml and use spEL - https://stackoverflow.com/a/35699678/5035525 – Ramanujan R Jul 03 '21 at 14:21

4 Answers4

12

Why don't you put @RequestMapping("/api") on all RestControllers?

@RestController
@RequestMapping("/api")
public class UserApi {
    @RequestMapping("/user")
    public String user() {
        ...
    }
}
Rod Lima
  • 1,509
  • 26
  • 30
6

You can try to create your custom annotation which would include @RestController and @RequestMapping:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@RestConntroller
@RequestMapping(value = "/api" )
@interface MyController {

}
jny
  • 8,007
  • 3
  • 37
  • 56
  • 1
    I think this would give the same problem if i put this annotation on a class and a "@RequesMapping" (because eg all the resources in that class are under the path /api/user), the two "@RequestMapping" annotations wouldn't be merged, or am I wrong in this? – Geert Olaerts Nov 15 '15 at 15:45
  • If you put one annotation on a class and the other one on the method, they should be merged. – jny Nov 15 '15 at 22:40
2

You can try using @path annotation to consider multiple URI as single URI.

@Path("sampleresource/{Filepath:.*}")
public interface SampleResource {
    @GET
    @Produces({ MediaType.TEXT_PLAIN })
    @Path("/hello")
    public Response sayHello();
}
0

See my answer to a similar question. How to configure a default @RestController URI prefix for all controllers? You can create a custom annotation and just perform mappings based on it.

Community
  • 1
  • 1
mh-dev
  • 5,264
  • 4
  • 25
  • 23