How to set base url for rest in spring boot?

JavaSpringRestSpring BootSpring Mvc

Java Problem Overview


I'm trying to to mix mvc and rest in a single spring boot project.

I want to set base path for all rest controllers (eg. example.com/api) in a single place (I don't want annotate each controller with @RequestMapping('api/products'), instead, just @RequestMapping('/products').

Mvc controllers should be accessible by example.com/whatever

Is it possible?

(I don't use spring data rest, just spring mvc)

Java Solutions


Solution 1 - Java

With Spring Boot 1.2+ (<2.0) all it takes is a single property in application.properties:

spring.data.rest.basePath=/api

ref link : https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri

For 2.x, use

server.servlet.context-path=/api

Solution 2 - Java

A bit late but the same question brought me here before reaching the answer so I post it here. Create (if you still don't have it) an application.properties and add

server.contextPath=/api

So in the previous example if you have a RestController with @RequestMapping("/test") you will access it like localhost:8080/api/test/{your_rest_method}

question source: how do i choose the url for my spring boot webapp

Solution 3 - Java

For spring boot framework version 2.0.4.RELEASE+. Add this line to application.properties

server.servlet.context-path=/api

Solution 4 - Java

I couldn't believe how complicate the answer to this seemingly simple question is. Here are some references:

There are many differnt things to consider:

  1. By setting server.context-path=/api in application.properties you can configure a prefix for everything.(Its server.context-path not server.contextPath !)
  2. Spring Data controllers annotated with @RepositoryRestController that expose a repository as rest endpoint will use the environment variable spring.data.rest.base-path in application.properties. But plain @RestController won't take this into account. According to the spring data rest documentation there is an annotation @BasePathAwareController that you can use for that. But I do have problems in connection with Spring-security when I try to secure such a controller. It is not found anymore.

Another workaround is a simple trick. You cannot prefix a static String in an annotation, but you can use expressions like this:

@RestController
public class PingController {

  /**
   * Simple is alive test
   * @return <pre>{"Hello":"World"}</pre>
   */
  @RequestMapping("${spring.data.rest.base-path}/_ping")
  public String isAlive() {
    return "{\"Hello\":\"World\"}";
  }
}

Solution 5 - Java

Try using a PathMatchConfigurer (Spring Boot 2.x):

@Configuration
public class WebMvcConfig implements WebMvcConfigurer  {

	@Override
	public void configurePathMatch(PathMatchConfigurer configurer) {
		configurer.addPathPrefix("api", HandlerTypePredicate.forAnnotation(RestController.class));
	}
}

Solution 6 - Java

Since this is the first google hit for the problem and I assume more people will search for this. There is a new option since Spring Boot '1.4.0'. It is now possible to define a custom RequestMappingHandlerMapping that allows to define a different path for classes annotated with @RestController

A different version with custom annotations that combines @RestController with @RequestMapping can be found at this blog post

@Configuration
public class WebConfig {
 
	@Bean
	public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
		return new WebMvcRegistrationsAdapter() {
			@Override
			public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
				return new RequestMappingHandlerMapping() {
					private final static String API_BASE_PATH = "api";
 
					@Override
					protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
						Class<?> beanType = method.getDeclaringClass();
						if (AnnotationUtils.findAnnotation(beanType, RestController.class) != null) {
							PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_BASE_PATH)
									.combine(mapping.getPatternsCondition());
 
							mapping = new RequestMappingInfo(mapping.getName(), apiPattern,
									mapping.getMethodsCondition(), mapping.getParamsCondition(),
									mapping.getHeadersCondition(), mapping.getConsumesCondition(),
									mapping.getProducesCondition(), mapping.getCustomCondition());
						}
 
						super.registerHandlerMethod(handler, method, mapping);
					}
				};
			}
		};
	}
}

Solution 7 - Java

You can create a custom annotation for your controllers:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RestController
@RequestMapping("/test")
public @interface MyRestController {
}

Use it instead of the usual @RestController on your controller classes and annotate methods with @RequestMapping.

Just tested - works in Spring 4.2!

Solution 8 - Java

For Boot 2.0.0+ this works for me: server.servlet.context-path = /api

Solution 9 - Java

I found a clean solution, which affects only rest controllers.

@SpringBootApplication
public class WebApp extends SpringBootServletInitializer {

    @Autowired
    private ApplicationContext context;

    @Bean
    public ServletRegistrationBean restApi() {
        XmlWebApplicationContext applicationContext = new XmlWebApplicationContext();
        applicationContext.setParent(context);
        applicationContext.setConfigLocation("classpath:/META-INF/rest.xml");

        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        dispatcherServlet.setApplicationContext(applicationContext);

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/rest/*");
        servletRegistrationBean.setName("restApi");

        return servletRegistrationBean;
    }

    static public void main(String[] args) throws Exception {
        SpringApplication.run(WebApp.class,args);
    }
}

Spring boot will register two dispatcher servlets - default dispatcherServlet for controllers, and restApi dispatcher for @RestControllers defined in rest.xml:

2016-06-07 09:06:16.205  INFO 17270 --- [           main] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'restApi' to [/rest/*]
2016-06-07 09:06:16.206  INFO 17270 --- [           main] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

The example rest.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="org.example.web.rest"/>
    <mvc:annotation-driven/>

    <!-- Configure to plugin JSON as request and response in method handler -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="jsonMessageConverter"/>
            </list>
        </property>
    </bean>

    <!-- Configure bean to convert JSON to POJO and vice versa -->
    <bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    </bean>
</beans>

But, you're not limited to:

  • use XmlWebApplicationContext, you may use any else context type available, ie. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • define jsonMessageConverter, messageConverters beans in rest context, they may be defined in parent context

Solution 10 - Java

I might be a bit late, BUT... I believe it is the best solution. Set it up in your application.yml (or analogical config file):

spring:
    data:
        rest:
            basePath: /api

As I can remember that's it - all of your repositories will be exposed beneath this URI.

Solution 11 - Java

I did some research on the differences of spring properties mentioned in this thread. Here are my findings if anybody is wondering.

spring.data.rest.basePath Property

spring.data.rest.basePath=/api

This property is specifically for Spring Data Rest projects. It won't work in a usual Spring MVC projects.

To change the context path in MVC projects, you can use those two properties mentioned below. Let me mention the differences too.

server.servlet.context-path Property

server.servlet.context-path=/api

This one sets the context path on your web servelet. This property perfectly works fine in both spring mvc and spring data rest projects. But, the differnce is the request url will be filter out before reaching spring interceptors. So it will respond with HTML on bad request. Not Spring's or your own custom JSON response (in @ResponseBodyAdvice annotated class) defined. To overcome that, you should use this property below.

spring.mvc.servlet.path Property

spring.mvc.servlet.path=/api

This will filter the request URL in spring mvc interceptors and will respond default/your custom JSON response if you invoke a bad request.

Conclusion:

So as the OP's question, I would suggest that he should use spring.mvc.servlet.path to change the context path.

Solution 12 - Java

You can create a base class with @RequestMapping("rest") annotations and extend all you other classes with this base class.

@RequestMapping("rest")
public abstract class BaseController {}

Now all classes that extend this base class will be accessible at rest/**.

Solution 13 - Java

With spring-boot 2.x you can configure in application.properties:

spring.mvc.servlet.path=/api

Solution 14 - Java

For those who use YAML configuration(application.yaml).

Note: this works only for Spring Boot 2.x.x

server:
  servlet:
    contextPath: /api

If you are still using Spring Boot 1.x

server:
  contextPath: /api

Solution 15 - Java

server.servlet.context-path=/api would be the solution I guess. I had the same issue and this got me solved. I used server.context-path. However, that seemed to be deprecated and I found that server.servlet.context-path solves the issue now. Another workaround I found was adding a base tag to my front end (H5) pages. I hope this helps someone out there.

Cheers

Solution 16 - Java

You can create a custom annotation for your controllers:

Use it instead of the usual @RestController on your controller classes and annotate methods with @RequestMapping.

Works fine in Spring 4.2!

Solution 17 - Java

For Spring WebFlux the approach is similar to Harald's, but with the obvious WebFlux configuration set up:

@Configuration
public class WebFluxConfig implements WebFluxConfigurer  {

   @Override
   public void configurePathMatching(PathMatchConfigurer configurer) {
       configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
   }
}

And for Kotlin it's:

@Configuration
class WebFluxConfig : WebFluxConfigurer {
    override fun configurePathMatching(configurer: PathMatchConfigurer) {
       configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
}

Solution 18 - Java

This solution applies if:

  1. You want to prefix RestController but not Controller.

  2. You are not using Spring Data Rest.

    @Configuration
    public class WebConfig extends WebMvcConfigurationSupport {
    
    @Override
    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
    	return new ApiAwareRequestMappingHandlerMapping();
    }
    
    private static class ApiAwareRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    
    	private static final String API_PATH_PREFIX = "api";
    
    	@Override
    	protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
    		Class<?> beanType = method.getDeclaringClass();
    		if (AnnotationUtils.findAnnotation(beanType, RestController.class) != null) {
    			PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_PATH_PREFIX)
    					.combine(mapping.getPatternsCondition());
    
    			mapping = new RequestMappingInfo(mapping.getName(), apiPattern, mapping.getMethodsCondition(),
    					mapping.getParamsCondition(), mapping.getHeadersCondition(), mapping.getConsumesCondition(),
    					mapping.getProducesCondition(), mapping.getCustomCondition());
    		}
    		super.registerHandlerMethod(handler, method, mapping);
    	}
    }
    

    }

This is similar to the solution posted by mh-dev, but I think this is a little cleaner and this should be supported on any version of Spring Boot 1.4.0+, including 2.0.0+.

Solution 19 - Java

Per Spring Data REST docs, if using application.properties, use this property to set your base path:

spring.data.rest.basePath=/api

But note that Spring uses relaxed binding, so this variation can be used:

spring.data.rest.base-path=/api

... or this one if you prefer:

spring.data.rest.base_path=/api

If using application.yml, you would use colons for key separators:

spring:
  data:
    rest:
      basePath: /api

(For reference, a related ticket was created in March 2018 to clarify the docs.)

Solution 20 - Java

worked server.contextPath=/path

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTeimurazView Question on Stackoverflow
Solution 1 - JavaSurojView Answer on Stackoverflow
Solution 2 - JavaOriolBGView Answer on Stackoverflow
Solution 3 - JavaduyuanchaoView Answer on Stackoverflow
Solution 4 - JavaRobertView Answer on Stackoverflow
Solution 5 - JavaHarald WendelView Answer on Stackoverflow
Solution 6 - Javamh-devView Answer on Stackoverflow
Solution 7 - JavaIlya NovoseltsevView Answer on Stackoverflow
Solution 8 - JavaJuan Carlos Vergara SantosView Answer on Stackoverflow
Solution 9 - JavakravemirView Answer on Stackoverflow
Solution 10 - JavathorinkorView Answer on Stackoverflow
Solution 11 - JavaThamidu AdikaramView Answer on Stackoverflow
Solution 12 - JavaSaket MehtaView Answer on Stackoverflow
Solution 13 - JavaBulgar SadykovView Answer on Stackoverflow
Solution 14 - JavaPrasanth RajendranView Answer on Stackoverflow
Solution 15 - JavaRahul TalrejaView Answer on Stackoverflow
Solution 16 - JavaPrerit NeemaView Answer on Stackoverflow
Solution 17 - JavaGregraView Answer on Stackoverflow
Solution 18 - JavaThe Gilbert Arenas DaggerView Answer on Stackoverflow
Solution 19 - JavaWoodchuckView Answer on Stackoverflow
Solution 20 - JavaPravin BansalView Answer on Stackoverflow