Kotlin Spring Boot form-urlencoded POST requests with a Map - spring-boot

I've just started playing around with Kotlin and Spring Boot and decided to write a simple endpoint that takes a form-urlencoded POST request. I didn't feel like writing an actual data class for the body, so I tried to just use a Map for the body, hoping I could just access key/value pairs. I first tried:
#RestController
class MyController {
#RequestMapping(value = "/endpoint", method = arrayOf(RequestMethod.POST),
consumes = arrayOf("application/x-www-form-urlencoded"))
fun myEndpoint(#RequestBody body: Map<String,String>): String {
// Do stuff
}
}
But that resulted in a 415 error about unsupported media type...which I read was due to the use of #RequestBody and form-urlencoded POSTs. I subsequently tried using the #ModelAttribute instead but then received
Failed to instantiate [java.util.Map]: Specified class is an interface
Hardly surprising as I was completely hacking. I also tried without any annotations for the body, but then none of the form parameters were injected. I know I could add a data class to solve this, but I'd like to know if this can be done generically using a Map as I've done a similar thing in Java before.
Thanks.

You need to annotate your body param with #RequestParam
#RequestMapping(value = "/endpoint", method = [(RequestMethod.POST)],
consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
fun myEndpoint(#RequestParam body: Map<String,String>): String {
return //...
}
(Also note that I removed the arrayOf calls in favour of array literals, which are available for annotations as of Kotlin 1.2)

Related

Different class types as RequestBody depending on RequestParam provided in a Spring Boot Controller?

So, I have a controller which takes in a request parameter and a body. The request body can be of various class types depending on the type of parameter. Currently I am using JsonNode for the body which works fine. Looks like this :
#PostMapping() public ResponseEntity<Response> save(#RequestParam("request type") RequestProcess process, #Valid #RequestBody JsonNode requestJson) {
I want to know whether it's possible to provide the body with the class type depending on the param provided. If yes how do I do it?
If this is not possible in REST, is there a chance I might be able to do this using GraphQl. I don't know much about GraphQL still researching.
TIA
The nearer you can reach is by using generics
class Controller < T > {
#PostMapping("/save")
ResponseEntity < Response > save(#RequestBody T requestJson) {}
}

Spring REST #RequestBody consume (XML or JSON) to POJO without annotations

I am writing a Springboot REST endpoint and want to consume XML or JSON requests for a simple service. In either case I want Spring to construct an #RequestBody pojo WITHOUT annotating any of the POJO. Is this OK? Safe? Performant?
I was reading this which told me about configuration by exception. To me this means if I structure my request to contain the exact name and case as the POJO member variables I want to populate the #RequestBody will be able to create my class SomeRequest.
If this is my REST endpoint:
#RequestMapping(value = GET_FOR_SOMETHING, method = RequestMethod.POST,
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE},,
produces = {MediaType.APPLICATION_JSON_VALUE})
public #ResponseBody
StatusResponse<Boolean> getMpdForReqest(#RequestBody SomeRequest request)
And this is my POJO:
public class SomeRequest {
String one;
String two;
public String getOne() {
return one;
}
public void setOne(String one) {
this.one = one;
}
public String getTwo() {
return two;
}
public void setTwo(String two) {
this.two = two;
}
}
My JSON request:
{
"one": "str",
"two": "str"
}
My XML request:
<SomeRequest>
<one>str</one>
<two>str</two>
</SomeRequest>
My question is: why should I not do this or is it perfectly fine?
Thank you all.
TLDR; It is perfectly fine.
Is this OK? Safe? Performant?
Yes, it is as performant as it's annotated cousin, if you take program efficiency into account.
If you take the Programmer efficiency into account, it is much more efficient as the developer doesn't have to deal with a bunch of annotations.
Speaking of Programmer efficiency, I would encourage you to use project Lombok instead of crapping your POJO with bunch of getter and setter methods, that's what cool kids do now a days.
Catch
This will work fine as long as your json fields are one word and small case.
When you have multi-word field name, Java standard is the camelCase and usually JSON standard is the snake_case. In this case, you can either have a Class level Annotation (one per class, so not much ugly). Or, since you are using spring boot, you can use an application wide property (spring.jackson.property-naming-strategy = SNAKE_CASE ).
If you have weird json field names with spaces in between, you might need to use #JsonProperty annotation. Remember, this is a perfectly valid json
{
"just a name with a space" : "123"
}
POJO as RequestBody works perfectly fine. Just note that Spring however will return 400 - Bad Request for every request that can not be mapped to the #RequestBody annoted object.

How to auto generate response fields that do not have POJO

We have a service that simply returns the json document on a GET request. Since we do not have the POJO for the response "model", it appears we won't be able to use the auto response fields generation "goodness".
One option for us is to create the Pojos (quite large, about 50 attributes) and a corresponding controller that uses the pojos. This is awkward as we now have to maintain the model and corresponding controller just so we can auto generate the model.
Any ideas on how we can still leverage some auto generation of the response fields would be greatly appreciated.
Here's the controller I'm referring to:
#RestController
#RequestMapping("/api")
public class ProductController {
#Autowired
ProductService productService;
#RequestMapping(value = { "/products/{ids}" }, method = { RequestMethod.GET },
produces = "application/json", headers={"accept=application/json"})
#Timed
#ExceptionMetered
#LogExecutionTime
public String getProductDetails(#PathVariable("id") String id) {
return productService.getProductDetails(id);
}
At the moment I see no way of leveraging the auto generation without putting additional effort into it. Spring Auto REST Docs works by inspecting POJOs with a Jackson visitor (static introspection without runtime information) and there is currently no way of deriving the JSON fields from a string (would be dynamic at runtime). Thus, I only see two options:
The approach that you already described: Creating the corresponding POJO and using it.
Using Spring REST Docs for the corresponding test and manually document each field in the test. Might be the better option here if you do not want to alter the production code.

What's the reason to use ResponseEntity<?> return type instead of simple ResponseEntity in Spring Controller?

I've seen a lot of examples of Spring Controllers implementation that use ResponseEntity<?> in order to return HTTP response that have a specific status code and optional body.
ResponseEntity<?> notation is present even in official Spring tutorials like the following one: Building REST services with Spring
What's the reason to use ResponseEntity<?> instead of simple ResponseEntity?
It's a little bit related to my previous question: SonarQube complains about using ResponseEntity with a wildcard
There is some explanation in What is a raw type and why shouldn't we use it? thread, but I'd like to pay more attention to ResponseEntity class and it's use in Spring Controllers.
Consider the following snippet of code where somethingService returns an Optional of Something class:
#GetMapping
ResponseEntity<?> getSomething() {
return somethingService.getSomething()
.map(smth -> new ResponseEntity<>(smth, HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
Is there any reason to leave a wildcard even if I don't get any profit from compiler checks since ResponseEntity(HttpStatus status) parametrises ResponseEntity with Object class?

5 levels of media type Spring REST

I am trying to apply CQRS principles on my REST API with domain-driven-design principles, using the 5 levels of Media Types, as explained in these articles:
https://www.infoq.com/articles/rest-api-on-cqrs
http://byterot.blogspot.ch/2012/12/5-levels-of-media-type-rest-csds.html
My technical context is Spring REST framework version 3.2.
Basically, i need to be able to map my commands using different "domain-model" media types.
Therefore, i would expect the following mapping to work:
#Controller
#RequestMapping("resources")
public class MyController {
#RequestMapping(value = "{id}", method = RequestMethod.PUT, consumes = "application/json;domain-model=CommandOne")
#ResponseBody
public void commandOne(#PathVariable Long id, #RequestBody CommandOne commandOne) {
LOG.info("Using command {}", commandOne);
}
#RequestMapping(value = "{id}", method = RequestMethod.PUT, consumes = "application/json;domain-model=CommandTwo")
#ResponseBody
public void commandTwo(#PathVariable Long id, #RequestBody CommandTwo commandTwo) {
LOG.info("Using command {}", commandTwo);
}
}
Problem is, I am getting mapping errors when requesting for a PUT:
PUT /resources/123
Content-Type: application/json;domain-model=CommandOne
Error is:
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path ...
Spring doesn't allow me to map the same uri the different domain-model Media Types. Any idea how could I achieve that? Am I missing something?
Many thanks
:o)
That's because the content-type is still the same application/json. Please look at Content-Type syntax
What you are passing as domain-model=CommandOne is just a parameter and Spring doesn't recognize as a difference to call the different methods.
This is described in more detail on answer
Does HTTP content negotiation respect media type parameters
This was submitted as a BUG to the Spring team but they closed with "Work as designed".
Unfortunately Spring can't treat this case currently.

Resources