How to parse RESTful API params with Dropwizard - java

Let's say I have:
#GET
public UserList fetch(#PathParam("user") String userId) {
// Do stuff here
}
Now, let's say I have my own type for userId, let's call it UserId. Is it possible to parse that String to UserId when it is passed into the fetch method, i.e.:
#GET
public UserList fetch(#PathParam("user") UserId userId) {
// Do stuff here
}
I realize I can parse the String once I am inside the method, but it would be more convenient that my method gets the type I want.

Well you've attempted to make a GET call with a request body is what I find not very helpful. Do read Paul's answer here -
you can send a body with GET, and no, it is never useful to do so
What would be good to practice is, to make a PUT or a POST call (PUT vs POST in REST) as follows -
#POST
#Path("/some-path/{some-query-param}")
public Response getDocuments(#ApiParam("user") UserId userId,
#PathParam("some-query-param") String queryParam) {
UserId userIdInstance = userId; // you can use the request body further
Note - The ApiParam annotation used is imported from the com.wordnik.swagger.annotations package. You can similarily use FormParam,QueryParam according to your source of input.

Dropwizard is using Jersey for HTTP<->Java POJO marshalling. You could use the various annotations from Jersey #*Param (#FormParam, #QueryParam, etc.) for some of the parameters.
If you need to use map/marshall to/from Java POJOs take a look at the test cases in Dropwizard:
#Path("/valid/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class ValidatingResource {
#POST
#Path("foo")
#Valid
public ValidRepresentation blah(#NotNull #Valid ValidRepresentation representation, #QueryParam("somethingelse") String xer) {
return new ValidRepresentation();
}
This defines an API endpoint responding to HTTP POST method which expects ValidRepresentation object and "somethingelse" as HTTP method query parameter. The endpoint WILL respond ONLY when supplied with JSON parameters and will return only JSON objects (#Produces and #Consumes on the class level). The #NotNull requires that object to be mandatory for the call to succeed and #Valid instructs Dropwizard to call Hibernate validator to validate the object before calling the endpoint.
The ValidRepresentation class is here:
package io.dropwizard.jersey.validation;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
public class ValidRepresentation {
#NotEmpty
private String name;
#JsonProperty
public String getName() {
return name;
}
#JsonProperty
public void setName(String name) {
this.name = name;
}
}
The POJO is using Jackson annotations to define how JSON representation of this object should look like. #NotEmtpy is annotation from Hibernate validator.
Dropwizard, Jersey and Jackson take care of the details. So for the basic stuff this is all that you need.

Related

Spring FeignClient - Treat RESTful xml response as JSON

I'm using Spring FeignClient to access a RESTful endpoint, the endpoint returns an xml,
I want to get the response as a JSON, which in turn will map to a POJO.
1) When I access the endpoint on the browser, I get response as below,
<ns3:Products xmlns:ns2="http://schemas.com/rest/core/v1" xmlns:ns3="http://schemas/prod/v1">
<ProductDetails>
<ProdId>1234</ProdId>
<ProdName>Some Text</ProdName>
</ProductDetails>
</ns3:Products>
2) #FeignClient(value = "productApi", url = "http://prodservice/resources/prod/v1")
public interface ProductApi {
#GetMapping(value="/products/{productId}", produces = "application/json")
ProductDetails getProductDetails(#PathVariable("productId") String productId)
// where, /products/{productId} refers the RESTful endpoint
// by mentioning, produces = "application/json", I believe the response xml would be converted to JSON Java POJO.
3) POJO
public class ProductDetails {
private String ProdId;
private String ProdName;
//...setters & getters
}
4) Service Layer
ProductDetails details = productApi.getProductDetails(productId);
In the 'details' object, both ProdId & ProdName are coming as null.
Am I missing anything here? Firstly, Is it possible to get response as JSON instead of XML?
If that RESTful service is programmed to return only xml-response, then you cannot ask it to give you json-based response.
But in your case the problem is with class where you want to map the result.
This xml response actually wraps ProductDetails tag into ns3:Products.
So you need to create another class which will hold a reference to ProductDetails object:
public class Product { //class name can be anything
private ProductDetails ProductDetails;
//getters, setters
}
Then change the type of getProductDetails method to Product.
If you still get nulls in your response, then it's probably because of ObjectMapper configuration. But you can always add #JsonProperty annotation for your fields (in
this case it would be #JsonProperty("ProductDetails") for ProductDetails field in Product, and #JsonProperty("ProdId") and #JsonProperty("ProdName") for fields in ProductDetails).

Jersey MOXy not parsing snake_case

I'm passing a JSON object from a PUT request to my server. The request itself works, however the fields in the JSON which have an underscore (snake_case) seem to bi ignored. The request outputs the received data to see what comes out, and the value with the underscore converts to camelCase, and doesn't get parsed. Here's the class:
Public User{
private int id;
private String name;
private int some_value;
}
The JSON object I pass to the PUT request:
{ "id":1, "name":John, "some_value":5 }
The PUT method only returns what MOXy caught in this case
#PUT
#Path("user")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public User addUser(User user){
return user;
}
And the output is:
{ "id":1, "name":John, "someValue":0 }
Notice how "some_value" changed to "someValue" and didn't get the actual value updated. Any idea on why this is happening?
MOXy follows Java Bean conventions by default, which suggest camel case. If you don't want to (or can't) use camel case, you can add an annotation to the field:
#XmlElement(name = "some_value")
private int some_value;
If you don't want to annotate all your fields, use an XMLNameTransformer.

JAX-RS Post method with multiple parameters

I want to make a JAX-RS web service using jersey implementation.
I need a post method with 3 parameters.
#POST
#Path ("/addData")
#produce(MediaType.Application_Json)
#Consume(MediaType.Application_JSON)
public User addData(int id, String name, String pass){
User u = new User();
u.setId(id);
u.setName(name);
u.setPass(pass);
return u;
}
#POST
#Path ("/addData")
#produce(MediaType.Application_Json)
#Consume(MediaType.Application_JSON)
public User addSingleData(int id){
User u = new User();
u.setId(id);
return u;
}
There is a separate User class as follow:
public class User{
int id;
String name;
String pass;
// here are the getter setter and constructors
}
First, can I use jersey-media-moxy-2.3.jar file for conversion to JSON (i dont want to use maven). because this jar file is not converting content to json but if i use maven its working fine without parameters in post method.
second, how to get param in body of method if i am using only one param. i.e. second method
third, how to use multiple params in post method.
fourth, in further i need to upload and download an image. how to do that.
last, i am not able to get data in json format.
NOTE: I am making web service for android mobile. i am going to consume it via andorid.
for RESTful API, you should not be relay on the usual web application parameter passing style,
... URL..?param=value
you should form a url in a way that, it make sense to access the resource:
for example:
#POST
#Path("/{courseId}/subjects/{"subjectId"}/description")
public Message get(#PathParam("courseId") String courseId,
#PathParam("subjectId") String subjectId) {
// ....
}
this resource endpoint is giving a way to post a new description for a specific subject under a specific course. So this is how you could access multiple Path parameters in the same Post request.
On the other hand, if you are talking about how to get value of all fields on your 'User' class then you should consider annotating the class with #XmlRootElement
#XmlRootElement
public class User{
int id;
String name;
String pass;
//empty contractors is mandatory in addition to the public getter and
// setters
public User(){
}
// here are the getter setter and constructors
}
now if you send with a POST method something like below : [JSON format] :
{
"id":"123"
"name":"user name"
"pass":"pass"
}
jersey will take of creating instance of User class with the data in the body of the request. which is the reason why you will need mandatory empty constructor in your User class, jersey will first create the instance of the class using the empty constructor and calls setters of each field to set values.
with that in place, if you simple put User in parameter of your method you will have object passed to your method.
#POST
#Path ("/addData")
#produce(MediaType.Application_Json)
#Consume(MediaType.Application_JSON)
public User addData(User newUser){
//do something
return newUser;
}

RESTFUL webservice spring, XML in stead of JSON?

I am trying to return an object as XML in spring, exactly like this guide: http://spring.io/guides/gs/rest-service/
Except that I want the object to return as xml instead of JSON.
Anyone know how I can do that?
Does Spring have any dependancies that can do this as easily for XML? Or, do I need to use a marshaller and then return the xml file some other way?
Spring supports JSON by default, but to support XML as well, do these steps -
In the class you plan to return as response, add xml annotations. for e.g.
#XmlRootElement(name = "response")
#XmlAccessorType(XmlAccessType.FIELD) => this is important, don't miss it.
public class Response {
#XmlElement
private Long status;
#XmlElement
private String error;
public Long getStatus() {
return status;
}
public void setStatus(Long status) {
this.status = status;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}
Add produces and consumes to your #RequestMapping on the restful method like below, this helps in making sure what kind of responses and request you support, if you only want response as xml, only put produces = "application/xml".
#RequestMapping(value = "/api", method = RequestMethod.POST, consumes = {"application/xml", "application/json"}, produces = {"application/xml", "application/json"})
public
Then, make sure you return the response object from your method call like below, you can add #ResponseBody just before return type but in my experience, my app worked fine without it.
public Response produceMessage(#PathVariable String topic, #RequestBody String message) {
return new Response();
}
Now, if you are supporting multiple produces types, then based on what client sent as the Accept in the HTTP request header, the spring restful service will return that type of response. If you only want to support xml, then only produce 'application/xml' and the response will always be xml.
If you use JAXB annotations in your bean to define #XmlRootElement and #XmlElement then it should marshall it xml. Spring will marshall the bean to xml when it sees:
Object annotated with JAXB
JAXB library existed in classpath
“mvc:annotation-driven” is enabled
Return method annotated with #ResponseBody
Follow this sample to know more:
http://www.mkyong.com/spring-mvc/spring-3-mvc-and-xml-example/

Spring Web MVC - validate individual request params

I'm running a webapp in Spring Web MVC 3.0 and I have a number of controller methods whose signatures are roughly as follows:
#RequestMapping(value = "/{level1}/{level2}/foo", method = RequestMethod.POST)
public ModelAndView createFoo(#PathVariable long level1,
#PathVariable long level2,
#RequestParam("foo_name") String fooname,
#RequestParam(value = "description", required = false) String description);
I'd like to add some validation - for example, description should be limited to a certain length or fooname should only contain certain characters. If this validation fails, I want to return a message to the user rather than just throw some unchecked exception (which would happen anyway if I let the data percolate down to the DAO layer). I'm aware of JSR303 but have not worked with it and don't quite understand how to apply it in a Spring context.
From what I understand, another option would be to bind the #RequestBody to an entire domain object and add validation constraints there, but currently my code is set up to accept individual parameters as shown above.
What is the most straightforward way to apply validation to input parameters using this approach?
This seems to be possible now (tried with Spring 4.1.2), see https://raymondhlee.wordpress.com/2015/08/29/validating-spring-mvc-request-mapping-method-parameters/
Extract from above page:
Add MethodValidationPostProcessor to Spring #Configuration class:
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
Add #Validated to controller class
Use #Size just before #RequestParam
#RequestMapping("/hi")
public String sayHi(#Size(max = 10, message = "name should at most 10 characters long") #RequestParam("name") String name) {
return "Hi " + name;
}
Handle ConstraintViolationException in an #ExceptionHandler method
There's nothing built in to do that, not yet anyway. With the current release versions you will still need to use the WebDataBinder to bind your parameters onto an object if you want automagic validation. It's worth learning to do if you're using SpringMVC, even if it's not your first choice for this task.
It looks something like this:
public ModelAndView createFoo(#PathVariable long level1,
#PathVariable long level2,
#Valid #ModelAttribute() FooWrapper fooWrapper,
BindingResult errors) {
if (errors.hasErrors() {
//handle errors, can just return if using Spring form:error tags.
}
}
public static class FooWrapper {
#NotNull
#Size(max=32)
private String fooName;
private String description;
//getset
}
If you have Hibernate Validator 4 or later on your classpath and use the default dispatcher setup it should "Just work."
Editing since the comments were getting kind of large:
Any Object that's in your method signature that's not one of the 'expected' ones Spring knows how to inject, such as HttpRequest, ModelMap, etc, will get data bound. This is accomplished for simple cases just by matching the request param names against bean property names and calling setters. The #ModelAttribute there is just a personal style thing, in this case it isn't doing anything. The JSR-303 integration with the #Valid on a method parameter wires in through the WebDataBinder. If you use #RequestBody, you're using an object marshaller based on the content type spring determines for the request body (usually just from the http header.) The dispatcher servlet (AnnotationMethodHandlerAdapter really) doesn't have a way to 'flip the validation switch' for any arbitrary marshaller. It just passes the web request content along to the message converter and gets back a Object. No BindingResult object is generated, so there's nowhere to set the Errors anyway.
You can still just inject your validator into the controller and run it on the object you get, it just doesn't have the magic integration with the #Valid on the request parameter populating the BindingResult for you.
If you have multiple request parameters that need to be validated (with Http GET or POST). You might as well create a custom model class and use #Valid along with #ModelAttribute to validate the parameters. This way you can use Hibernate Validator or javax.validator api to validate the params. It goes something like this:
Request Method:
#RequestMapping(value="/doSomething", method=RequestMethod.GET)
public Model dosomething(#Valid #ModelAttribute ModelRequest modelRequest, BindingResult result, Model model) {
if (result.hasErrors()) {
throw new SomeException("invalid request params");
}
//to access the request params
modelRequest.getFirstParam();
modelRequest.getSecondParam();
...
}
ModelRequest class:
class ModelRequest {
#NotNull
private String firstParam;
#Size(min = 1, max = 10, message = "You messed up!")
private String secondParam;
//Setters and getters
public void setFirstParam (String firstParam) {
this.firstParam = firstParam;
}
public String getFirstParam() {
return firstParam;
}
...
}
Hope that helps.

Categories

Resources