I'd like to create a controller which will return Page object. I will need page Pageable to have with page number and its size (it cannot be larger than 50) and some variables which will be search criteria. If this was a POST request, it could look as follows:
public Page<SomeDto) getDto(#RequestBody #Valid RequestDto requestDto, Page pageRequest)
However, it is a GET request so #RequestBody cannot/shouldn't be used.
Additionally, I would like to have something akin to #Valid so that Spring will automatically reject bad request.
I'm wondering whether:
it is possible to and if so how to implement this and have already created Dto from values taken from URL (#PathVariable or #RequestParam) as if it was POST request which maps body to object.
I'd like to avoid using some kind of that code:
public String updateFoos(#RequestParam Map<String,String> allParams) {}
if what is described in 1st is not possible, what solution would be closest as to meeting those requirements?
You can have a HTTP body (and therefore a #RequestBody) for every HTTP requests no matter what HTTP method is used. However, it is not a good REST API design to use a HTTP body for GET request (cf. https://martinfowler.com/articles/richardsonMaturityModel.html)
You can do bean validation with #PathVariable or #RequestParam arguments, you just have to put the annotation you want next to these annotations
Related
Hello i am looking if i can handle with only one RestController method multiple params...
with controllers method it could be done... but i couldnt find project with 2 like that.
#PostMapping(value ="upload")
public upload(#RequestParam MultipartFile file,#RequestParam List<String> myParams ){
some code here ....
return;
}
I am just wondering if is also a good practise ... having two deferent type of objects in same controller and if its possible,,, any idea????
Simple answer: Yes, that's possible.
But as you asked for good practice, here's some context:
It is very helpful to understand how HTTP actually transports data.
If your request uses GET as request method, parameters are added to the URL as a query string. That could look like this: http://example.com/index?param1=value1¶m2=value2
In this case, Spring maps the key-value pairs from the query string to your method arguments. But this will only work for text.
If you're using POST, the data is sent inside the request body. How that is encoded depends on the media type of your data. For example, the default media type application/x-www-form-urlencoded would encode the data to the same query string as above.
If you want to upload mixed-type form data like a file/blob along with some textual parameters, your data should be encoded with multipart/form-data.
As long as the request body contains a key-value format, Spring Boot will still be able to distinguish and map the parameters via #RequestParam (If the keys don't differ from your attribute names, you don't even need to assign a name to the value attribute).
I highly recommend you to take a look at the #RequestBody and #RequestPart annotations as i think it often is best practice to use a model class (DTO) for the whole request body (or rather the form, semantically), especially if there are a lot of parameters to process.
You will need to specify the names of the variables.
#PostMapping(value ="upload")
public upload(
#RequestParam(value = "file") MultipartFile file,
#RequestParam(value = "myParams") List<String> myParams
){
some code here ....
return;
}
a question to validation of put calls to a REST endpoint using spring boot and javax.validation (not the spring validation).
You have the following method in the resource:
#PutMapping(...)
public Response getResult(#RequestBody #Valid myBody, #PathVariable #MyIdValidation long id) {
}
When I call the method, myBody gets validated and I get a MethodArgumentNotValidException in my exception handler. But parameter id gets not validated!
Only if myBody is valid, id gets validated as well.
The only solution I found is to not use #Valid, and implement the validation of the body myself.
Are there better solutions?
TIA
Kibu
I don't think its doable by Spring MVC framework itself because framework handles #RequestBody and others like #RequestParam or #PathVariable differently by using different components. Also, both pieces need to be disconnected because you might not like to validate all arguments of a method.
#RequestBody is handled by org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor and validations are called from there & for params or path variable validations are done by org.springframework.validation.beanvalidation.MethodValidationInterceptor.
So in my opinion, method arguments of a controller method are handled one by one by framework & are disconnected in logic so these validations can't be clubbed together.
I've put some effort into this issue and started a project on github
It's possible to validate in one stop, but you need a different approach. Check out the project and test it.
Kibu
I use org.springframework.security.web.csrf.CookieCsrfTokenRepository to secure my spring based web application from CSRF attacks. This enables all the Controller methods to be called only by passing a X-XSRF-TOKEN header or a _csrf request parameter.
So in order for me get the response of a GET URL in browser, I will have to write something like the below in browser address bar.
http://localhost:8080/api/someresource?_csrf=99e3b824-d0c9-409d-91ee-c7ccbdce313f&filter1=value1&filter2=value2&so=on
However, Some of these urls have filter mechanism based on the request parameters and unfortunately this extra _csrf parameter breaks that logic.
As I see it, this request parameter should be needed if the request had passed the csrf validation. But I couldn't do anything in the documentation to remove the _csrf request parameter on the application level.
At the moment, I do something like below.
#ResponseStatus(OK)
#RequestMapping(method = RequestMethod.GET, value = "/search/advanced")
#ResponseBody
public ResponseVO advancedSearch( #RequestParam MultiValueMap<String, String> queryParameters, Pageable pageable) {
queryParameters.remove(MyApplicatonConstants.CSRF_PARAM_NAME); //this line is the hack that I wrote
return doStuffAndGetFilteredData(queryParameters);
}
This implementation has its drawbacks.
I will have to change all 143 controller methods to have this one line on the top.
I have to remember to add this for new methods in future.
it's a cheap hack and there should be some better and cleaner way of doing it.
Is there a way I can acheive this without rewriting that one line again and again?
Note:
I fully understand that I can use CURL or Postman so I can pass X-XSRF-TOKEN in header. But it's not as quick as opening the URL in a new tab.
I have tried to find the answer to this, but I cannot seem to find what I am looking for. So I apologize if this question already exists.
PROBLEM:
I want to be able to access the request type of a request inside of a generic method within my Controller.
DESCRIPTION:
Using Spring ROO and Spring MVC, I have developed a small web service that will respond with certain tidbits from a database when queried. In one of my controller classes, I have some methods that handle some variety of GET, PUT, POST, etc., for the URIs that are mapped within the #RequestMapping parameter.
For example:
#RequestMapping(method = RequestMethod.Get, value = "/foo/bar")
#ResponseBody
public ResponseEntity<String> getFooBar() {
// stuff
}
If a request is made to the web service that it is not currently mapped, a 405 error is returned (which is correct), but I want to return more information along with a 405 response. Maybe respond with something like:
"I know you tried to execute a [some method], but this path only handles [list of proper methods]."
So I wrote a short method that only has the RequestMapping:
#RequestMapping(value = "/foo/bar")
I have found that the method with this mapping will catch all unhandled request types. But I am having trouble accessing the information of the request, specifically the type, from within the method.
QUESTION:
A. How can I access the request type from within the method? OR
B. Is this the right approach? What would be the right approach?
EDIT
ANSWER:
I added a HttpServletRequestobject to the method parameters. I was able to access the method type from that.
I tried using HttpRequest, but it didn't seem to like that much.
Thanks all!
You can add a method parameter of HttpServletRequest, but I think you'd be better off continuing to reply with 405. A client should then make an HTTP OPTIONS call (see How to handle HTTP OPTIONS with Spring MVC?) and you can return the list of allowed methods there.
A. you can access request if you mentioned it as parameter in controller method
public ... getFooBar(HttpRequest request) {
...
}
B. you do not need to add any other description as the 405 status is descriptive.
In answer to "A", just add "HttpRequest req" as an additional argument to your controller methods. Spring will automatically inject a reference to the request, and you can play with headers to your heart's content.
In answer to "B" - "What would be the right approach", how about this?
In order to return that 405, Spring has raised a MethodArgumentNotValidException. You can provide custom handling for this like so:
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public MyMethodArgumentMessage handleMathodArgumentNotValidException(
MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
MyMethodArgumentMessage myMessage =
new MyMethodArgumentMessage(result.getFieldErrors());
return myMessage;
}
You should take a look at the #ExceptionHandler annotation. This lets you add methods such as the following to your controller. You can define your own exceptions and appropriate custom handlers for them. I use it to return well-structured XML and JSON from REST services. Although for it to work, you need to throw specific exceptions from your controller methods.
A good walk-through of using this was provided by Petri Kainulkainen in his blog:
http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/
I have a Spring MVC controller which is servicing GET requests, to perform a search.
These requests have many optional parameters which may be passed on the query string.
For example:
#Data
public class SimpleSearchRequest implements SearchRequest {
private String term;
private List<Status> stati;
#JsonDeserialize(using=DateRangeDeserializer.class)
private Range<DateTime> dateRange;
}
If I were using a POST or PUT for this, I could nicely marshall the inbound request using a #RequestBody. However, because I'm using a GET, this doesn't seem to fit.
Instead, it seems I'm required to list all the possible parameters on the method signature as #RequestParam(required=false).
Aside from leading to ugly method signatures, I'm also losing out on all sorts of OO goodness by not using classes here.
Attempting to use #RequestBody fails (understandably so), and as discussed here and here, using an actual request body on a GET is not desirable.
Is there a way to get Spring MVC to support marshalling multiple #RequestParam's to a strongly typed object on GET requests?
It seems the answer was to simply remove the annotation.
This worked:
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody List<Result> search(SearchRequest request) {}