ReSTful service getting contradict due to path parameter value has forward slash - rest

I have API like this-
/objectname/name
/objectname/collection/id
Both API's are indirectly related.
Problem occurs when calling first API with name value as "A/B Type". So rest controller actually calling second API rather first (/objectname/A/B Type) because forward slash. How to deal with this situation.
As a side note I am encoding the parameters values.
I developed the restful services using SpringBoot and RestTemplate.

The conflict comes by specifying the name directly in the resource path and passed to the function as a #PathVariable.
Your code looks something like this:
#RequestMapping(value = "objectname/{name}", method = RequestMethod.GET)
public String yourMethodName(#PathVariable String name){
return name;
}
What I would recommend in order to avoid this kind of conflict is (if you're allowed to modify the #RestController or #RepositoryRestResource layers) to pass the value of the object in a #RequestParam
For instance:
#RequestMapping(value = "/objectname", method = RequestMethod.GET)
public String yourMethodName(#RequestParam(name = "name", required = true) String name){
return name;
}
That said, When you are constructing your the request using RestTemplate then you should url encode your name (A%2FB%20Testing) and construct the following url:
http://localhost:8080/objectname?name=A%2FB%20Testing
I tested this locally and worked alright for me.

Related

Is it possible for a restful webservice to have a parameter in the url?

I was instructed to create webservices ( with Spring-Boot ). My colleague gave me the url of the webservice and it looks like this : http://172.20.40.4:8080/Oxalys_WS/stock/ITM=1559
In general we create a RestController with the url :
#RestController
#RequestMapping("stock")
public class StockController {
#Autowired
private StockService stockService;
#GetMapping(value = "/{code}", produces = "application/json")
public JsonModel getByCode(#PathVariable String code) {
JsonModel jsonModel = new JsonModel();
final Map<String, Object> data = new HashMap<>();
List<Stock> stock = stockService.getByCode(code);
data.put("stock", stock);
data.put("stockTotal", stockService.getTotal(code));
jsonModel.setDatas(data);
return jsonModel;
}
}
So is it normal to create a Restful Spring-Boot webservice with a parameter in the url ?
Spring provides parameter in two standard way.
Query Param : http://172.20.40.4:8080/Oxalys_WS/stock?ITM=1559
Path Variable : http://172.20.40.4:8080/Oxalys_WS/stock/1559
Query Param :- It is a typical old way to pass some value as QueryParam with using of some variable starts with ?(Question Mark) and value is assigned using =(equals).
PathVariable :- this is a newer pattern introduce for REST-api Services. URL must be structured such in a way that this should not look too messy if multiple parameters need to pass within a URL.
For more info Navigate this link
Yes, you can have the one in your URL
When you are required to have the path variable, you can give in the Request URL

Getting method name related to a rest service

I wanted to know if there exist a way of retrieving the actual method name associated to a rest service provided. Lets suppose my url is http://localhost:8080/v1/mytesturl now i want to retrieve the actual method name that is associated with this url.
Actually we are maintaining some key/value pair specific to the method that we have created and i need to make some checks based on the method name that gets executed using these values.
Plz let me know if there exist some way to do that..
Simply get the method name from the Object class.
#RestController
#RequestMapping("")
public class HomeController {
#RequestMapping("/mytesturl")
#ResponseBody
public String getMethodName() {
return new Object(){}.getClass().getEnclosingMethod().getName();
}
}
i got the solution by using this
Map<RequestMappingInfo, HandlerMethod> handlerMethods = RequestMappingHandlerMapping.getHandlerMethods();
HandlerExecutionChain handler = RequestMappingHandlerMapping.getHandler(requestr);
HandlerMethod handler1 = null;
if(Objects.nonNull(handler)){
handler1 = (HandlerMethod) handler.getHandler();
handler1.getMethod().getName()
}
this provide me with what i wanted..

Spring MVC REST

I'm using Spring MVC and I have a controller mapped to a url lets call it example. I also have a method called show that allows me to view one of my examples based on an id.
#RequestMapping("/example")
#RequestMapping(value = "/{id}", produces = "text/html")
public String show(#PathVariable("id") String id, Model model) {
//Do some stuff and return a view
}
The problem is that the id is a URI and it has forward slashes. (e.g. test/case/version/sample might be an id so the resulting url is example/test/case/version/sample) so as a result my application gives me an error "Requested resource not found". I can't easily change the format of these ids. It's a list given to me that I have to work with. Is there a way around this? Thanks in Advance.
You can try using Regular expressions on the #PathVariable.
Like this from the Spring Docs:
#RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
public void handle(#PathVariable String version, #PathVariable String extension) {
// ...
}
}
You'll just have to think on a regular expression that matches the "example/test/case/version/sample" that is your expression.
See the title: "URI Template Patterns with Regular Expressions"
on this page: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html for more information

Spring MVC GET/redirect/POST

Say I have 2 Spring MVC services:
#RequestMapping(value = "/firstMethod/{param}", method = RequestMethod.GET)
public String firstMethod(#PathVariable String param) {
// ...
// somehow add a POST param
return "redirect:/secondMethod";
}
#RequestMapping(value = "/secondMethod", method = RequestMethod.POST)
public String secondMethod(#RequestParam String param) {
// ...
return "mypage";
}
Could redirect the first method call to second(POST) method?
Using second method as GET or using session is undesirable.
Thanks for your responses!
You should not redirect a HTTP GET to a HTTP POST. HTTP GET and HTTP POST are two different things. They are expected to behave very differently (GET is safe, idempotent and cacheable. POST is idempotent). For more see for example HTTP GET and POST semantics and limitations or http://www.w3schools.com/tags/ref_httpmethods.asp.
What you can do is this: annotate secondMethod also with RequestMethod.GET. Then you should be able to make the desired redirect.
#RequestMapping(value = "/secondMethod", method = {RequestMethod.GET, RequestMethod.POST})
public String secondMethod(#RequestParam String param) {
...
}
But be aware that secondMethod can then be called through HTTP GET requests.

ASP.NET Mvc - nullable parameters and comma as separator

How should I define route in my global.asax to be able use nullable parameters and coma as separator?
I'm trying to implement routing rule for my search users page like
"{Controller}/{Action},{name},{page},{status}"
Full entry from the Global.asax:
routes.MapRoute(
"Search",
"{controller}/{action},{name},{page},{status}",
new { controller = "User", action = "Find",
name = UrlParameter.Optional,
page = UrlParameter.Optional,
status = UrlParameter.Optional }
);
Routine defined like above works fine when I'm entering all parameters, but when some parameters are equal to null routing fails (for example "user/find,,,")
According to Clicktricity comment bellow - the singature of action method that handes the request:
public ActionResult Find(string userName, int? page, int? status)
{
// [...] some actions to handle the request
}
On the beginning I was testing the route by VS debugger, now I'm using route debugger described on Phil's Haack blog. The tool confirm - that routing with null values is not properly handled (or I'm doing something wrong ;) )
As far as I know .Net routing doesn't let you do multiple nullable parameters like that. Multiple parameters will only work if they are missing working backwards from the end and with the separator also missing so you'd get matches on
user/find,bob,2,live
user/find,bob,2
user/find,bob
user/find
It'd be a lot easier to use querystrings for what you're trying to do.
Edit based on comment:
If this is necessary then you could try doing it this way (though it's not a nice approach)
Change your path to match
{Controller}/{Action},{*parameters}
Make sure to put a constraint on the action and controller so this is limited to as few as possible.
Rename each action that would take your full list to something else, adding a standard prefix to each one would be the cleanest way, and add the [NonAction] attribute. Add a new method with the original name that takes a string, this string is a comma separated string of your variables. In this method split the string and return the original action passing in the values from the split.
So you go from:
public ActionResult Find(string name, int page, string status){
//Do stuff here
return View(result);
}
To
public ActionResult Find(string parameters){
string name;
int? page;
string status;
//split parameters and parse into variables
return FindAction(name, page, status);
}
[NonAction]
public ActionResult FindAction(string parameters){
//Do what you did in your previous Find action
return View(results);
}