Using Spring Boot I've build a toy REST service with a single resource like so:
@RestController
@RequestMapping("/checkout")
public class CheckoutRestController {
@PostMapping("/book")
public boolean buyBook(@RequestParam CreditCard creditCard, @RequestParam ShippingAddress shippingAddress) {
return true;
}
}
Both CreditCard
and ShippingAddress
are POJOs (plain old Java objects) that I've coded up).
I've tried posting to this endpoint with this payload:
{
"creditCard" : {
"nameOnCard":"foo",
"number":12345678,
"expiryMonth":12,
"expiryYear":2018,
"ccv":100
},
"shippingAddress" : {
"steert":"foor",
"houseNumber":"1a",
"city":"bar",
"state":"bazz",
"country":"buzz",
"zipCode":"booz"
},
}
But I get an error:
{
"timestamp": "2018-03-13T11:36:52.745+0000",
"status": 400,
"error": "Bad Request",
"message": "Required CreditCard parameter 'creditCard' is not present",
"path": "/checkout/book"
}
I know a workaround would be to wrap both POJOs in a request wrapper but I'd rather not unless I really have to.
Is it possible to post two @RequestParam annotated objects? If so, what would the JSON look like?
Note − For building a RESTful Web Services, we need to add the Spring Boot Starter Web dependency into the build configuration file.
Simply put, the @RequestBody annotation maps the HttpRequest body to a transfer or domain object, enabling automatic deserialization of the inbound HttpRequest body onto a Java object. Spring automatically deserializes the JSON into a Java type, assuming an appropriate one is specified.
@RequestParam
parameters are query parameters, not body parameters.
This means that your method:
@PostMapping("/book")
public boolean buyBook(@RequestParam CreditCard creditCard, @RequestParam
ShippingAddress shippingAddress) {
return true;
}
Expects the following request:
POST /checkout/book?creditCard=<...>&shippingAddress=<...>
However, Spring doesn't know how to convert a String
query parameter to CreditCard
or to ShippingAddress
.
You might solve this by implementing a Converter
, as follows:
public class StringToCreditCardConverter implements Converter<String, CreditCard> {
@Override
public CreditCard convert(String source) {
<...>
}
}
However, I do not recommend this as it is not the standard for request bodies and would cause quite a lot of confusion and maintainability issues.
Instead, the recommended way is as follows:
@PostMapping("/book")
public boolean buyBook(@RequestBody BookCreationRequest bookCreationRequest) {
CreditCard creditCard = bookCreationRequest.getCreditCard();
ShippingAddress shippingAddress = bookCreationRequest.getShippingAddress();
...
}
With the bookCreationRequest
containing the CreditCard
and ShippingAddress
fields (note: you could use e.g. lombok
to reduce the boilerplate code):
public class BookCreationRequest {
private ShippingAddress shippingAddress;
private CreditCredit creditCard;
public ShippingAddress getShippingAddress() {...}
public CreditCard getCreditCard() {...}
public BookCreationRequest(ShippingAddress shippingAddress, CreditCard creditCard) {
this.creditCard = creditCard;
this.shippingAddress = shippingAddress;
}
Which would then expect a request JSON as follows:
POST /checkout/book
Payload:
{
"creditCard": {
...
},
"shippingAddress": {
...
}
}
Note that there can only be a single @RequestBody
parameter in a request.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With