I have a URI string inside the request that I am supposed to make. How to extract it and write a proper controller.
markerURI = marker://markerType/markerValue
Request:
POST /books/123/markers/marker://big/yellow
I have written below rest controller for the above request:
#PostMapping("/books/{id}/markers/{markerURI:^marker.*}")
public void assignMarker(
#PathVariable("id") String id,
#PathVariable("markerURI") String markerURI
)
but i'm not able to get markerURI=marker://big/yellow inside markerURI variable. The request show 404 Not found error. Is there any way to do this. It's a requirement so can't do any hacks.
Edit:
markerURI can contain attributes like marker://markerType/markerValue?attr1=val1&attr2=val2
As per https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-requestmapping-uri-templates
You can have your url pattern in below pattern
"/resources/ima?e.png" - match one character in a path segment
"/resources/*.png" - match zero or more characters in a path segment
"/resources/**" - match multiple path segments
"/projects/{project}/versions" - match a path segment and capture it as a variable
"/projects/{project:[a-z]+}/versions" - match and capture a variable with a regex
but your url pattern is defined as a url inside a url, for that I suggest you to use below method and concatenate your result after fetching the values from uri as pathvariable.
#PostMapping("/books/{id}/markers/{marker:[a-z]+}://{markerType:[a-z]+}/{markerValue:[a-z]+}")
public void assignMarker(#PathVariable("id") String id,#PathVariable("marker") String marker,
#PathVariable("markerType") String markerType,
#PathVariable("markerValue") String markerValue) {
String markerUri = "/"+marker+"://"+markerType+"/"+markerValue;
System.out.println(markerUri);
}
Related
I am trying to change the REST call's #PathVariable. The existing Path Variable is formed by combination of three parameters. The change is to handle Path Variable formed by combination of two parameters. I need this change to be documented in swagger with the earlier shown as Deprecated.
I have tried to use both Path Variable with one as #Deprecated like below
#Parameter(description = "x_y_z - x is first ID, y is second ID, z is third ID", required=false )
#Deprecated #PathVariable String x_y_z,
#Parameter(description = "x_y - x is first ID, y is second ID", required=true )
#PathVariable String x_y)
The have changed request mapping value from /aaa/bbb/{x_y_z} to below
#RequestMapping(value = "/aaa/bbb/{x_y}", method = RequestMethod.GET, produces = "application/json"
With above changes the request fails with 500 error, may be since it is expecting two Path Variables. But the swagger documentation is as expected.
I tried to remove #PathVariable for x_y_z. The request is processed as expected and the swagger now shows x_y_z as deprecated but shows the parameter as (query) instead of (path)
Any suggestions please
Assuming an #RestController and that Swagger understands #Deprecated for a method:
#Deprecated
#GetMapping("/aaa/bbb/{x:\\d+}_{y:\\d+}_{z:\\d+}")
public ResponseEntity<MessageResponse> getStuff(#PathVariable String x,
#PathVariable String y,
#PathVariable(name = "z", required = false) String z) {
return getNewStuff(x, y); //send to the other method and ignore z
}
#GetMapping("/aaa/bbb/{x:\\d+}_{y:\\d+}")
public ResponseEntity<MessageResponse> getNewStuff(#PathVariable String x,
#PathVariable String y) {
// do stuff for x and y by default
return ResponseEntity.ok(new MessageResponse("this method is supported for " + x + " and " + y));
}
The RegEx should look for digits as the path variables, interspersed with underscores.
NB: leaving this part of the answer if Swagger works with it instead with the understanding that it could be deprecated:
#PathVariable #Parameter(description = "x_y_z - x is first ID, y is second ID, z is third ID", deprecated = true) String z
Deprecating the original method and introducing a new method with the correct parameters but different RequestMapping could also be a valid workaround.
The other part to note is that it is more common to use slashes as the delimiter rather than underscores in Spring (e.g., /aaa/bbb/x/y). You also may wish to include a validator that fits your requirements.
I have created an endpoint that accepts a string in its request param
#GetMapping(value = "/validate")
private void validateExpression(#RequestParam(value = "expression") String expression) {
System.out.println(expression);
// code to validate the input string
}
While sending the request from postman as
https://localhost:8443/validate?expression=Y07607=Curr_month:Y07606/Curr_month:Y07608
// lets say this is a valid input
console displays as
Y07607=Curr_month:Y07606/Curr_month:Y07608 Valid
But when i send
https://localhost:8443/validate?expression=Y07607=Curr_month:Y07606+Curr_month:Y07608
//which is also an valid input
console displays as
Y07607=Curr_month:Y07606 Curr_month:Y07608 Invalid
I am not understanding why "+" is not accepted as parameter.
"+" just vanishes till it reaches the api! Why?
I suggest to add this regular expression to your code to handle '+' char :
#GetMapping(value = "/validate")
private void validateExpression(#RequestParam(value = "expression:.+") String expression) {
System.out.println(expression);
// code to validate the input string
}
I didn't find any solution but the reason is because + is a special character in a URL escape for spaces. Thats why it is replacing + with a " " i.e. a space.
So apparently I have to encode it from my front-end
Its wise to encode special characters in a URL. Characters like \ or :, etc.
For + the format or value is %2. You can read more about URL encoding here. This is actually the preferred method because these special characters can sometimes cause unintended events to occur, like / or = which can mean something else in the URL.
And you need not worry about manually decoding it in the backend or server because it is automatically decoded, in most cases and frameworks. In your case, I assume you are using Spring Boot, so you don't need to worry about decoding.
I have a very odd situation. I have an API endpoint which has to accept requests to list all the resources available for the given endpoint and list a specific resource. The endpoint looks like this :
/v1/patients
I can call this without passing any path variables and it will list all patient records. Here comes the special case - If I want to fetch only one patient, I have to pass in the Patient number as path variable - and My patient number looks something like this - 2019/patientname/October/27 - and that is the problem.
when I pass the above number as path variable, I will not get the resource I wanted, instead Spring considers the slashes "/" as separators.
Example :
/v1/patients/2019/patientname/October/27
And I am getting the response like given path is not found - of course there is no path like that.
Is there a possibility of Ignoring all the slashes in between this one Patient number?
Edit : There is no possibility of changing the Patient number as it is part of a very old and legacy code-base, on which the whole system is running.
Edit 2 - URL encoding cannot be used in this situation - this patient number has to be passed in as it is - Situation is very insane.
You could try something like:
#GetMapping("/v1/patients/{year}/{name}/{month}/{day}")
public ResponseEntity<Patient> getPatient(#PathVariable Integer year,
#PathVariable String name,
#PathVariable String month,
#PathVariable Integer day) {
String patientNumber = year + "/" + name + "/" + month + "/" + day;
...
}
And here's something that may also work:
#GetMapping("/v1/patients/**")
public ResponseEntity<Patient> getPatient(HttpServletRequest request) {
String patientNumner = (String)
request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
...
}
Can I put /** wildcard in a middle of request mapping such as: "/some/resource/**/somthing"
In Spring 3 I can do this
#RequestMapping("/some/resource/**")
to map
/some/resource/A -> ControllerMethod1
/some/resource/A/B -> ControllerMethod1
/some/resource/A/B/C/D/E/F -> ControllerMethod1
for any number of paths parts
However this mapping is too greedy and will not allow me to map a sub URL #RequestMapping("/some/resource/**/somthing") to another controller such as
/some/resource/A/somthing -> ControllerMethod2
/some/resource/A/B/somthing -> ControllerMethod2
/some/resource/A/B/C/D/E/F/somthing -> ControllerMethod2
How can i do this?
I thinks it's not possible to use that ant style in url mapping as you require, because it will stop on the next path separator character '/'.
I would suggest you to try 16.3.2.2. URI Template Patterns with Regular Expressions in order to map just the last part of the request (haven't tried this approach yet).
Also you can match the rest of the request using PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, and apply some expression there. Check this post.
Otherwise you should use request parameters to match that condition 16.3.2.6. Request Parameters and Header Values.
You can narrow request matching through request parameter conditions such as "myParam", "!myParam", or "myParam=myValue". The first two test for request parameter presense/absence and the third for a specific parameter value. Here is an example with a request parameter value condition.
In this case you will map something like that using params
#RequestMapping(value = {"/some/resource/**"}, params="somthing")
or use the annotation request parameter with not required attribute in method signature:
public void test(#RequestParam(value = "somthing", required=false) String str) {
I need to pass this filepath over via route to my actionmethod:
<p>#car.Name</p>
so for example #car.ContainerPath is a string of "34_Creating%20Cars%20Forms/Exercise%20Cars/Audi%202010%20Parts%20Reference.pdf"
I need to escape this somehow I think? I would prefer not to send this over url but with a hyperlink I don't see a way not to.
UPDATE:
For additional info, here's the actionmethod it's going to:
public string GetFileZipDownloadUrl(CarViewModel model, string fileContainerPath)
{
string downloadUrl = string.Empty;
downloadUrl = GetFileZipDownloadUrl(model.CarId,fileContainerPath, model.UserId);
return downloadUrl;
}
so I'm sending over for that fileContainerPath paths like this in the url for that #car.ContainerPath param:
"55_Creating Cars Forms/Exercise Cars/Audi Parts Reference.pdf"
so the route url before it's requested looks like this when formed in that hyperlink:
http://Cars/55/55_Creating Cars Forms/Exercise Cars/Audi Parts Reference.pdf/20/Url
My action method just needs to use that path to go get a reference to a file under the hood.
If you want to just get rid of %20 in the url use encoding/decoding like in #Xander's answer. However if any of your data is very dynamic and can have weird characters you should consider adding a Safe() and Unsafe() methods that will strip out all the "Dangerous" characters for url, and then turn it back to original value.
Raw Url:
HttpUtility.UrlEncode(rawurl);
Decode encoded url:
HttpUtility.UrlDecode(encodedurl);
http://msdn.microsoft.com/en-us/library/system.web.httputility.urlencode.aspx
http://msdn.microsoft.com/en-us/library/system.web.httputility.urldecode.aspx