Why is plus(+) decoded to space ( ) in url path with springboot rest controller? - spring

When calling GET http://localhost:8080/things/ZhaD2lk27XQPRJtwrABltd+UTWXcbnY%2FTrpxGP7VDVo= my Spring Boot application RestController with a request handler like this:
#RequestMapping("/things/{thingId}")
public ResponseEntity<Thing> getThing(
#PathVariable String thingId) {
System.out.println("thingId=" + thingId);
...
results in the following being printed ZhaD2lk27XQPRJtwrABltd UTWXcbnY/TrpxGP7VDVo= instead of what I would have expected ZhaD2lk27XQPRJtwrABltd+UTWXcbnY/TrpxGP7VDVo=.
As you can see, the plus is being turned into a space. This should not happen with the path part, only the query part. This is why the Spring UriComponentsBuilder.build().encode() I'm using to build the URL doesn't turn the plus into %2B.
I needed to tweak the application already to get the encoded slash (/) to work. See REST Endpoint unreachable if ID in URL contains %2F for details.
I'm using SpringBoot 1.4.4.RELEASE which uses Tomcat embed 8.5.11.
I have tried calling the service from Spring RestTemplate, Postman and Chrome. Same results in all cases, the plus is turned into a space

I was able to resolve after identifying that my IDE had automagically added spring-boot-starter-undertow to the POM file. I did not exclude spring-boot-starter-tomcat from spring-boot-starter-web so I'm not sure what was happening under the covers but removing the spring-boot-starter-undertow dependency fixed the issue.

Related

How to remove context-root from generated swagger

I have am application that has a context-root set (property: quarkus.http.root-path).
Using quarkus-resteasy-reactive-jackson, a resource was created with a #Path annotation.
Now I want to generate OpenAPI documentation for my resource.
As I want to deploy this into a API gateway, I require a server property with a context root in the swagger.
I added a server entry using the mp.openapi.servers property.
The problem now appears that when there is a root-path property, the generated swagger resource path includes this root path, e.g.
quarkus.http.root-path=/sample
mp.openapi.servers=http://localhost:8080/sample
Resource annotated with #Path("resource")
It seems that the resource path includes the root-path.
So importing this swagger into the API gateway (or just clicking on the Try button), results in a url of http://localhost:8080/sample/sample/resource being attempted which ofc does not exist.
Is there a way to not to add the root-path to the resource endpoint in swagger? (I tried using mp.openapi.extensions.application-path.disable=true, but this had no effect)
I managed to get past this by doing the following:
dont set quarkus.http.root-path
quarkus.rest.path=/sample
quarkus.http.non-application-root-path=/sample/q
mp.openapi.servers=https://localhost:8080/sample
So just want to know if anyone know of a better way of doing this?

URI Spring Encoding Issue

I have a query param that contains "+" sign, I encoded it and pass it to a Spring Controller but the controller interprets it as space thus failing the API.
Sample
Name = test+fetch
URI passed from browser: abc.org/fetch?name=test%2Bfetch
How Controller receives it
name = test fetch
there is nothing with test fetch and thus the API fails
Is there a way we can solve this issue, decoding the param after spring resolves it doesn't solve the issue
Edit:
Updated Controller Code
#GetMapping("fetch")
public String fetch(#RequestParam("name") String name){
return something;
}
I created an application using https://start.spring.io/ and your controller, and the encoding works as it's supposed to.
https://www.dropbox.com/s/z9rbe2gtpvzebqv/url-encoding.zip?dl=1
I think there's something before your application, may be a proxy, web server or Spring Gateway, that's decoding the parameter. Otherwise, download the app I created and prove that the problem exists.

How to define explicit mapping for swagger-ui.html in spring boot application

I have an issue integrating swagger-ui (swagger2) into my spring-boot application. It seems as though the default location for swagger-ui being on the root is conflicting with an endpoint.
For example, my base path is foobar (full url: locahost:8080/foobar/). One of my endpoints has a path variable that can be any number (making the endpoint url: localhost:8080/foobar/{number} or localhost:8080/foobar/123 as an example). This seems to conflict with swagger-ui.html, as when I then try to hit locahost:8080/foobar/swagger-ui.html, spring complains, thinking 'swagger-ui.html' is the path variable for that endpoint.
I was curious if there was a way to define an explicit mapping for swagger-ui, so that spring won't think that I'm just inputting a path variable to the other endpoint? I ideally don't want to modify the foobar/{number} path at all, and would like to either make an explicit mapping for swagger-ui, or change the path for swagger-ui itself. Any help is appreciated. Thanks!

spring boot: separate REST from static content

I'm using spring-boot-starter-data-rest and spring-boot-starter-web.
I've made a simple project using a CrudRepository, letting spring boot generate the rest request mappings.
Now, I want to add a client -- making the rest calls -- live under ./.
Hence, I'm trying to prefix the paths for the rest calls (and only those!) with /api.
I've tried the answers from :
How to specify prefix for all controllers in Spring Boot?
using settings in the application.properties file
server.contextPath=/api/*
spring.data.rest.basePath=/api/*.
But still the static content (e.g. index.html, *.js, *.css) is not fetched using ./. There urls are also prefixed by "/api/".
The rest calls are properly served under /api/foos.
Is there a way to tell spring not to treat urls that lead to sources located in src/main/resources/public as 'rest-controllers'?
Update
Setting the property
spring.data.rest.basePath=/api/*
works perfectly. (I still had a programmatic bean configuration in my sandbox overriding this setting).
Spring controllers are made for serving both HTML and JSON/XML. The first one is done via Spring MVC Views and some template engine like Thymeleaf, the latter is handled entirely by Spring and #RestController.
There's no way to have a context path for only the controllers that returns JSON or XML data, and not for the other controllers as well, this also goes for static content. What you typically do is have some static variable containing the prefix you want for your APIs, and the use that in the controller's #RequestMapping. i.e.
#RestController
#RequestMapping(MyConstants.API_LATEST + "/bookings")
public class MyBookingsController {
...
}
You probably want to approach the prefix problem with something along these lines anyway. It is common to have to support older API versions when you have breaking changes, at least for some time.

Spring boot embedded tomcat behaves differently to standalone

I have a Spring boot application that exposes a REST API via Spring MVC.
When I run my application locally using the embedded tomcat I can access resources with a trailing slash on the end - e.g POST /resource/
However, when I deploy the war to a standalone tomcat instance, I get a 404 if I include the trailing slash on the URL, but a success without the trailing slash - e.g POST /resource.
The embedded tomcat works with or without the trailing slash.
My request mapping is
#RequestMapping(value = "/resource", method = RequestMethod.POST)
I've tried all sorts of configuration options including
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
matcher.setUseTrailingSlashMatch(true);
}
The only difference I can see is the embedded tomcat is v8 and the standalone is v7. Both running the exact same sourcecode but behaving differently.
Can anyone advise on how to correct this issue?
Thanks
I was able to resolve the issue. For anyone else finding this post...
For some reason, Tomcat 7 was trying to map requests with a trailing slash to a welcome file (index.jsp). It also does not recognise the endpoint if the request contains a trailing slash unless you specifically set a request mapping for "/" despite the setUseTrailingSlashMatch match to true.
This behavior was not mirrored in my embedded tomcat (v8).
I resolved the issue by removing the welcome files from the web.xml and updating my request mapping to:
#RequestMapping(value = {"/resource","/resource/"}, method = RequestMethod.POST)

Resources