JAX-RS #POST Syntax - java

I have not used #POST before and am not sure about the syntax and how to test. Here's what I have now:
#GET
#Path("classroomAssignmentId/{classroomAssignmentId}/classroomId/{classroomId}/assignmentName/{assignmentName}/assignmentDesc/{assignmentDesc}/assignmentDueDt/{assignmentDueDt}/assignmentDocument/{assignmentDocument}/assignmentStatusId/{assignmentStatusId}/updatedBy/{updatedBy}")
#Produces(MediaType.APPLICATION_JSON)
public ClassroomAssignment getCandidatesAsJson( #PathParam("classroomAssignmentId") int classroomAssignmentId
,#PathParam("classroomId") int classroomId
,#PathParam("assignmentName") String assignmentName
,#PathParam("assignmentDesc") String assignmentDesc
,#PathParam("assignmentDueDt") String assignmentDueDt
,#PathParam("assignmentDocument") String assignmentDocument
,#PathParam("assignmentStatusId") int assignmentStatusId
,#PathParam("assignmentTypeId") int assignmentTypeId
,#PathParam("updatedBy") String updatedBy)
I want to change the #GET to #POST. Need help with syntax and how to test the WS call through a browser.

There are two issues here.
First, merely wanting to express your parameters differently is insufficient for changing the semantics of your call. A POST is fundamentally different from a GET, and both semantics are very clearly defined in REST. You shouldn't switch just for convenience sake.
But second, if you find the theory pedantic and just care about how to practically get this done, you will use something like this:
#POST
#Path("/classroom-assignment)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public ClassroomAssignment getCandidatesAsJson(CandidateObject myObject) {
...
}
Then you will need your JAX-RS provider (RESTEasy, Spring MVC, Restlet, etc.) to perform automatic deserialization of JSON (typically with Jackson) to the CandidateObject POJO, which will have getters and setters mapping to the fields in your original query string of your GET.
At least that's the default serialization, which will be sufficient and easiest.
You will also have a ClassroomAssignment POJO, and your JSON serializer (again typically Jackson) will convert that POJO to JSON.
But ultimately, if a GET worked before, you should probably keep things as GET. Just rethink your design and how the GET call is made.

Related

Single POJO for different REST operations with validation

I'm designing a REST service and am running into the issue that for a given object, I have multiple "states".
The object as it arrives on the initial POST operation.
The Object I store in our DB
The Object I return on a GET
The Object I expect on a PATCH
e.g.
class MyObject {
// Unwanted on POST
// Required on PATCH
// Included on GET
#JsonProperty("id")
private UUID id;
// Everywhere
#NonNull
#JsonProperty("name")
private String name;
// Field I need for internal processing but don't want included in REST.
private AuditTrail stuff;
#JsonCreator
#Builder
public MyObject(...) { ... }
}
...
#Get
public ResponseEntity myFunction(HttpServletRequest request,
#RequestBody #Valid MyObject requestBody) {
...
}
The issue I am running into is that on POST, when the id is omitted, the deserialization fails. I got around it using #JsonIgnoreProperties(), but now on PATCH, where I do want the id present, things work if it is omitted.
Another alternative we toyed with was to have two objects. The first one with the common fields for POST and the other extending from it with the rest, but it feel messy, especially as we deal with objects more complex than the simple example.
It's not actually a problem since I validate and sanitize inputs anyway, but I was wondering if there is a clean way in Jackson to solve this issue.
If you are planning a rest service then you don't need the id in the body anyway. The id will come from the url as a pathvariable:
POST myobjects
GET myobjects/{id}
PATCH myobjects/{id}

List of possible overloads for Jersey JAX-RS resources

I'm using Jersey to implement a JAX-RS resource. I've seen lots of different examples on Stack Overflow, various blogs and the Jersey User Guide.
I would like to know what the different overloads can be for a given resource handler. Is there a single source where these are documented?
For example, the following handles an HTTP POST request. The request body is captured as a MultivaluedMap.
#POST
public Response httpPostRequest(MultivaluedMap<String, String> body)
{
...
}
Alternatively, the following overload captures the body as a single String.
#POST
public Response httpPostRequest(String body)
{
...
}
There are other overloads too. How many are there and where are they documented?
It is just a normal Java method that has one or more annotations associated with it. The signature of the method has no particular constraints placed on it by Jersey.
Having said that, you will want to make sure that the various annotations (e.g., #Produces, #Consumes, #PathParam, #QueryParam) are applied to data types that Jersey knows how to map. For example, Jersey has no problem with mapping #PathParam to String or long. Jersey can also work with Java classes that have JAXB annotations, so your method signature can include a JAXB type combined with #Consumes(MediaType.APPLICATION_XML) and Jersey will convert the request content from an XML document to the JAXB Java class.
For example:
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("somepath")
public Foos getFoosByQuery(#PathParam("businessName") String businessName,
#PathParam("businessUnitName") String businessUnitName, #PathParam("fileType") String fileType,
#QueryParam("from") String fromString, #QueryParam("to") String toString,
#DefaultValue("10") #QueryParam("interval") int intervalMinutes,
#DefaultValue("1000") #QueryParam("limit") int limit,
#DefaultValue("false") #QueryParam("errors") boolean errors) {
Here, we see that we have many parameters (with types String, int and boolean) and a return type that is a JAXB-annotated POJO. Jersey pulls the #PathParam values from the path, the #QueryParam values from the query string and converts the return value into an XML document and includes it as the content of the response.
I will also note that the name of the method can be anything we want, so the concept of "overloading" is orthogonal to Jersey. The normal Java overloading rules apply.
It should be obvious from this example that you cannot enumerate all of the possible "overloads" that you can use with Jersey.
Perhaps a different question regarding all of the possible type mappings that Jersey can do would be more in line with what you are looking for.

how can i typecast Request body into desired entity in REST API Controller

my motive is to write one generic save method in REST API. User will send the entity in Request body such that depending upon Request Mapping String it should be converted to entity.
Why i am want this, because in my case there are as many as 50-60 entities and as per my understanding i have to write many controllers.
I am trying to achieve something like this.
#RequestMapping(value = "/{entity}", method = RequestMethod.POST)
#ResponseBody
public Object performSave(#PathVariable String entity
#RequestBody Object entity) {
switch(entity){
case "employee"
return employeeService.save((Employee)entity);
case "Boss"
return bossService.save((Boss)entity);
default:
return null;
}
but i am not able to do that because Spring cannot convert the JSON Request into java.lang.Object.
what possible solutions i have ?
If my question do not make sense to you, please let me know ,i will provide additional details.
Thanks in advance.
I don't think that is possible as the underlying mapper would need the concrete class which the json is parsed to. The parameter is simply a reference to the actual object.
Something to take note of is that when using REST and getting the benefit from it is not only having simple urls to call. One has to design APIs to be RESTfull. I would advice you to read up on that concept before going down this path you are heading.
It can be done with only one controller.
One possible implementation would be using JsonSubTypes and Java inheritance.
It is done by moddeling request body objects (entities, in the original question) that extend an abstract class. Request body parameter in the controller's method then has the type of the abstract class.

RESTful thru JAX-RS, what is the common usage for #QueryParam and #Consume?

I am a new comer in terms of web services. I am tasked to convert an existing software component to a web service. I did some research and I decided to use JAX-RS. I am having a difficulty to decide when to use #QueryParam and when to use #Consume because they seems to be able to achieve the same goal.
For example, let say I have a method named read() and it takes a book as an argument.
public class AReader { public void read(Book book){...} }
public class Book { public String author; public String name; }
When translating this using JAX-RS annotation, I could either
Use #POST and #QueryParam to accept the author and name parameter or
Use #POST and #Consumes to consume a text representation of Book in XML or JSON format in the body.
My question is what is the common usage for #QueryParam and #Consume. Is this just a personal preference or there is a common practice?
I found a lot information about usage of #PathParam and #QueryParam but not #QueryParam and #Consumes.
Thanks in advance...
Query parameters are ideally best suited for representing aspects of requests that have nothing to do with a resource representation.
For example, if you are designing a RESTful web service, and if you're creating a new Book via a POST request, then the body of the request should ideally contain the resource representation in the desired media type - application/json, text/xml, application/x-www-form-urlencoded etc. Providing the resource representation via query parameters would not be on the lines of how HTTP-based REST APIs are designed. Additionally, query parameters can be omitted and thus the provided resource representation is incomplete, which would be against the design principles that require complete resource representations to be provided in POST and PUT operations.
Query paremeters would be more suitable for GET requests. Say you want a paginated collection of requests, then you would accept requests like /books?start=0&pagesize=10 to obtain the first 10 books.
You are right when you say you can use #QueryParam and #Consumes to achieve a common goal, but be aware that the semantics of those annotations are very different.
In your case, since you are interested in just two values, both approaches are equivalents in my opinion. If you were working with more complex objects (i.e. POJO with several attributes), I would suggest you let JAX-RS implementations take care of object marshalling/unmarshalling annotating the methods with #Consumes and/or #Produces.
This sample code:
#GET
#Path("/books")
public void books(#PathParam("title") String title, #PathParam("author") String author, #PathParam("ISBN") String isbn, #PathParam("category") String category, #PathParam("price") String price) {
Book book = new Book(title, author, isbn, category, price);
...
}
could be reduced to
#POST
#Path("/books")
#Consumes(MediaType.APPLICATION_XML)
public void books(Book newBook) {
Book book = newBook;
...
}
Additionally, REST architecture brings a new semantics to HTTP verbs and codes. According to its guidelines, you are not supposed to use #POST with #PathParam or even #GET to modify a resource. Please, refer to this link for a brief explanation but feel free to explore it in more details (you can start here).
In JAX-RS, you can use #QueryParam annotation to inject URI query parameter into Java method. for example,
/users/query?url=nini.com
In above URI pattern, query parameter is “url=nini.com“, and you can get the url value with #QueryParam("url").
======
""http://docs.oracle.com/cd/E19776-01/820-4867/ggqqr/ ""

Converting #RequestBody to an object

Guys, Well I have done enough research still I can't find the solution to this.
In a nutshell, I'm simply passing url encoded form data to the Controller method and trying to convert it as a domain object which has Date and integers.
#RequestMapping(value = "/savePassport", method = RequestMethod.POST)
public #ResponseBody
AjaxResponse savePassport(#RequestBody StaffPassport passport, HttpServletResponse response) {
// Some operations.
}
The Staff Passport looks like this:
import java.sql.Date;
public class StaffPassport {
private int staffId;
private String passportNumber;
private String placeOfIssue;
private Date issueDate;
private Date expiryDate;
private String spouseName;
private String oldPassportRef;
private String visaInfo;
private String description;
//gets/sets
}
When I invoke the /savePassport, I get unsupported media exception. I guess it's related to casting.
I can't this working right. Of course I can catch individual form data using #RequestParam and manually do the casting but that's not the point of a framework isn't it?
Where am I going wrong? And you are right. I'm a beginner in Spring, but I love it.
Looks like you're using the wrong annotation. #RequestBody is for taking a request that has arbitrary content in its body,such as JSON, some application defined XML, comma separated variables.. whatever. And using a marshaller that you configure in the dispatcher servlet to turn it into objects.
If all you want to do is ask Spring to bind a plain old form post onto the backing object for you, the correct annotation to put on the method parameter is #ModelAttribute.
If you are posting a JSON Object with jQuery and you want Spring to be able to process it with #RequestBody, use JSON.stringify(....) in your data. Here an example:
var data = { "id": 3, "name": "test" }
$.post("processJsonData.html",JSON.stringify(data), function(data){
...
}
);
If you don't use the JSON.stringify() then you will submit the data as form data and Spring will tell you that you have an unsupported media type.
First of all be sure that you have
<mvc:annotation-driven />
in your Spring configuration file. This is mandatory for working with JSOn in SPring MVC.
Second, I recommend you to test wether request to the server has application/json content type. I belive Fiddler2 will help you to do so.
Third, but I'm not sure about it, Try to change Date items in your POJO from SQL type to regular java type.
UPDATE:
just looked at the Form and it seems like your "Accept" HTTP Header should be also application/json. Please test this issue with Fiddler2 as well.
I assume that you are posting JSON and want Spring to convert to StaffPassport. If you are getting an Unsupported media exception, it is because Spring could not figure out an appropriate way to perform the conversion.
For Spring to convert JSON, it needs Jackson -- make sure you have the Jackson jars in your project. If this is a Maven based project you can add the jackson-mapper-asl artifact ID to your pom.xml. This should give you the jackson-mapper and jackson-core jars.
Edit: I should mention that this applies to Spring 3 (I recently ran into this problem). I'm not sure what else is required for previous versions of Spring.
Check into HttpMessageConverter interface and its implementations. You could write your own implementation of it to convert it to the domain model you want. By the time the control gets to your method, you can access it as if your domain model object is passed.
Ok, I think I should refine my answer. I do not have direct experience of using it in a spring-mvc project but spring-integration. I am pretty sure the applicable media type (application/x-url-form-encoded) is already handled and converted to MultiMap by Spring framework; so, retrieve the values from that just like any other map with the key value being your form variable and populate your business model.
HTH.

Categories

Resources