This is my first try at writting service from scratch. I'm using RestController and Java Spring to create a service which generates pdf based on parameters which are passed when calling the service. Service is called with one parameter, but can be called with two different variables (one is registry number and the other is identificator) and depending on which one of those two is passed, service generates the same JSON but different service is called in background of my program (one call works with IDN and one works with regNum).
So far I have this:
#RequestMapping(value = "/generatePdf/{idn}", method = RequestMethod.GET, produces = "application/pdf")
public String generatePdf(#PathVariable String idn) {
//logic
}
My question is this. What is the best solution for this problem?
Do I make separate method with different name and mapping?
Should I create a flag which checks which type od data is sent? Or, something third, feel free to suggest.
I would recommend you to create separate method instead of adding the additional flag:
API will be more readable and understandable, eg: GET /pdfByIdn/{idn} and GET /pdfByRN/{rn}
Easy to add additional cases, without modification of existing methods
Its make more sense to use separate service classes to different approaches to generate PDF's
#RequestMapping(value = "/generatePdf/{idn}/{rgn}", method =
RequestMethod.GET,
produces = "application/pdf")
public String generatePdf(#PathVariable(required = false) String idn,
#PathVariable(required = false) String rgn)
{
if(idn.equals(null){
//logic
}else {
//logic
}
}
Related
I am working on designing Rest API. I have a existing end point say
#RequestMapping(value = "/games", params = {"tId", "sId"}, method = RequestMethod.GET)
which search games . Now I need to search games based on different set of attributes. I have two options:
a) Use same endpoint "/games" but takes different set of input params like
#RequestMapping(value = "/games", params = {"tId", "day"}, method = RequestMethod.GET)
2) I should create a seperate endpoint(URL) for this.
Kindly Advice.
Also if I go with second option, what should be the endpoint name should be.
Given that both intended endpoints/endpoint return the same thing, I might opt for keeping a single REST endpoint which accepts all possible parameters:
#RequestMapping(value = "/games", params = {"tId", "sId", "day"}, method = RequestMethod.GET)
You can add logic to the handler method which checks to see which incoming parameters have been defined, and based on that choose the appropriate course of action. You may need to add logic which detects if someone is misuing the REST endpoint and return an error in that case (e.g. by defining both sId and day).
Can you please share me the standard method, if any to prevent one method call before the client call another. For example: I have the following two methods in my controller
#RequestMapping(value = “/save”, method = RequestMethod.PUT)
#ResponseBody
public String save(string temp){
return service.update(temp);
}
#RequestMapping(value = “/save/confirm”, method = RequestMethod.PUT)
#ResponseBody
public String ValidateInfo(string temp){
return service.update(temp);
}
So the question is what is the standard way to prevent the client side from calling the save method before calling the validateInfo method using REST API features. Assuming both methods do serious of stuff in the server side.
The client, which might be a different piece of software that you don't control, can make any call at any time. So you can't really prevent a client from making calls. This suggests that your design is a bit flawed.
I would suggest validating the user input as part of the save method - this is usually more secure and robust. If the validation fails, you should consider how you want to notify the client. For example, you could return an error message.
You can return a token from method1 which needs to supplied as parameter to method2..In this way you can make sure that method2 is always called after method1
I am working on a Spring-MVC application in which there are 2 parts. It is basically a note taking application with 2 modes, one is groupMode and other is personalMode. Now they both have their different dao's, serviceImpl in the backend, but they are in one controller view.
I have a boolean value to set, to know which mode is the user currently in, to perform CRUD operations in the specific database table. Now As both group modes are personal modes are in the same view, I have to make my methods so they can accept objects from either of the mode. Does spring support accepting only one object even if I declare 2 in model attribute. Here is the example of what I want to achieve :
#RequestMapping(value = "/section/add", method = RequestMethod.POST)
public
#ResponseBody
boolean addSection(#ModelAttribute("section") Section section, #ModelAttribute("groupsection") GroupSection groupSection,Model model) {
if(boolean == true){
this.groupSectionService.addGroupSection(groupSection);
model.addAttribute("groupsection", new GroupSection());
} else{
this.sectionService.addSection(section);
model.addAttribute("section", new Section());
}
return true;
}
Is this possible, I will always be sending one object from the front-end. Thanks a lot. Any pointers or suggestions are welcome.
Whenever there is such a if-statement that "split" the complete controller method, like yours, I have the feeling that one controller method should been replaced by two methods, one for each case.
The easiest, and most straight forward solution would been using two different URLs.
But maybe you have some reason for using the same URL, then I would have two different controller methods with the same URL but a different params Attribute in #RequestMapping
#RequestMapping(value = "/section/add",
method = RequestMethod.POST
params="createGroupSection=false")
#ResponseBody
public boolean addSection(#ModelAttribute("section") Section section) {...}
#RequestMapping(value = "/section/add",
method = RequestMethod.POST
params="createGroupSection=true")
#ResponseBody
public boolean addGroupSection(#ModelAttribute("section") Section section) {...}
I'm going to implement a RESTful webservice using Spring.
Let it be an ordinary PUT method, something like this:
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
In such a case input JSON format (if it corresponds to Foo class) will be successfully converted to Foo instance with no extra efforts, or error will be issued in case of wrong format.
But I'd like to make the service able to consume two different types of formats using same method (e.g. PUT) and same URL (e.g. /foo).
So that it possibly looked like:
//PUT method #1
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
//PUT method #2
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody FooExtra fooExtra) {
fooService.update(fooExtra);
}
and Spring converter tried to convert input JSON not only in Foo but in FooExtra as well and invoked corresponding PUT method depending on input format.
In fact, I tried to implement it exactly as it described above but without success. Is it even possible? Maybe, I need some kind of "trick"?
What is the best (and the most proper) way to achieve such behavior? Of course, I could always make two different URLs but I'd like to know whether it is possible with the same one.
Your attempt didn't work simply because Spring tried to match your methods against the request, by looking at url and method type, which are in both cases the same. It does not work like overloading in Java; argument types do not differentiate your methods.
But there are good news. SpringMVC can also examine request headers and request parameters when trying to match your handler methods. Since what you want to pass is actually pure metadata -an alternative format type of the same information- it makes perfect sense to use a custom request header. It's very easy to add custom headers when using a rest api. See the following link for JAX-RS: Adding a custom header.
Now in your server side you should configure the handler methods as:
//PUT method #1
#RequestMapping(method=RequestMethod.PUT, value="/foo", headers="returnType=Foo")
public #ResponseBody Foo updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
//PUT method #2
#RequestMapping(method=RequestMethod.PUT, value="/foo", headers="returnType=FooExtra")
public #ResponseBody FooExtra updateFoo(#RequestBody FooExtra fooExtra) {
fooService.update(fooExtra);
}
Note also that if you want to access a return value with #ResponseBody you have to return your object, otherwise make the methods void
For understanding it we should think how Spring works, it uses Dispatcher Servlet. I don't think that spring does "combine" work for different types of input.
So my answer will be: "trick" with two different urls ;)
Suppose I want to handle patch requests and write code like that:
#RequestMapping(value = "/{id}",
method = RequestMethod.PATCH)
#Consumes("application/json")
#Produces("application/json")
public SomeResponse updateType(#PathVariable String id,
#RequestBody ContactDto contact) throws Throwable {
//extract parameters from contact
}
So the problem is how recognize what parameters are set from patch requests? At first look it is obvious to write like this:
if (contact.getHobby() != null) {
updateHobby(contact.getHobby());
}
But what if I want to set hobby to null via json or delete it from current contact? So I pass a json string without hobby property and upper code does not work.
So the problem is - how separate properties that are set to null from those which are not set at all?
The body of a PATCH request should describe the changes to be made on the target entity. You shouldn't pass the entity itself.
With PATCH, however, the enclosed entity contains a set of
instructions describing how a resource currently residing on the
origin server should be modified to produce a new version.
For example, if you wanted to remove the hobby, you could pass some JSON like
{"removeHobby":true}
Your application would parse that and know it had to alter the entity by removing its hobby value.