MediaType of REST - java

I am beginner in REST web services.
I wrote a program of REST to display the HTML or XML. The #Path annotation's value is #Path("{typeDocument}"). There are two methods for GET :
#GET
#Produces(MediaType.TEXT_XML)
public String getXml(#PathParam("typeDocument") String typeDocument)
to display XML file,
and
#GET
#Produces(MediaType.TEXT_HTML)
public String getHtml(#PathParam("typeDocument") String typeDocument)
to display HTML.
The browser Firefox always excutes getHtml() when URL is either
http://localhost:8080/sources/html or http://localhost:8080/sources/xml
But IE always excutes getXml().
How to excute the correct method, as defined by URL, in different browser ?

try using MediaType.APPLICATION_XML instead of TEXT_XML.
That being said, this isn't the best use of JAX-RS - especially if you're using RestEASY or any other implementation with JAXB support.
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/{typeDocument}")
public MyObject getXml(#PathParam("typeDocument") String typeDocument) {
myObjectService.get(typeDocument);
}
#XmlRootElement(name="myObject")
public class MyObject {
// Some properties
}
would be a much easier method to maintain. You can also use JSPs for the HTML.
See http://java.dzone.com/articles/resteasy-spring for a good example (using Spring).

Related

spring boot application with both front end and restful

I am Planning to build a web application using Spring Boot as restful service.
my spring boot web restful application should be accessible by other application as well. In case if any one accessing the rest service from other application then my application should work as expected.
#Controller
public class GreetingController {
#RequestMapping("/greeting")
public String greeting(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
In above example if call is made from outside of application then the rest service should return JSON output.
One way we can have some variable to distinguish as request variable. But I do not want like that. Please share some standard way.
Appreciate your help.
Idiomatic way is to rely on Accept request header.
If requester presents Accept: application/json then return him JSON data (REST API).
If requester provides you with Accept: application/xhtml+xml return him HTML (web frontend).
Implementation-wise you should is to be done use #RequestMapping with consumes argument. You need two methods. If business logic for both paths is the same then in could be reused. Business logic should reside in another method or in separate #Service. Business logic on its own should not know, care or rely on transport protocol (HTTP), serialization of request response or presentation. Business logic should just work with POJOs and leave serialization to #Controller.
#Controller
#RequestMapping("/greeting")
public class GreetingController {
#RequestMapping(consumes="application/json")
#ResponseBody //required if you want to return POJO (spring will serialize it to response body)
public void rest() {
//return POJO, it will be serialized to JSON. or serialize pojo
directly and return response with manually set body and headers.
}
#RequestMapping(consumes="application/xhtml+xml")
public void html() {
//populate model, return string pointing to HTML to View
}
}
I suggest creating two controller classes, the second one using #RestController. Then, have two paths; the second could be "rs/greeting". This approach, which separates the Web and RESTful concerns, is much more extensible and doesn't require any weird headers that most clients don't want to deal with.

How to use ".." to pass URL parameters into Jersey?

I've encountered this URL RESTful query:
http://rest.ensembl.org/map/cdna/ENST00000288602/100..300?content-type=application/json
Where 100..300 are parameters that says: "from 100 to 300" (indexes). I can change those parameters as i'd like.
I want to have this kind of query parameter passing in my web-service as well. How can I annotate this in a Jersey API, and how do I get the parameter values?
You can use #Path annotation to map the 100..300 kind of URL.
For example, the below code works fine for me.
#Path("/Test")
#Component
public class TestRestfulService {
#GET
#Path("/100..200")
#Produces(MediaType.APPLICATION_JSON)
public String getText(){
return "Success";
}
}
Using the above code you can access the method by localhost:8080/test/100..200.
Hope this solves the problem!

How to change the response content type for a Dropwizard REST service?

I took a look at the Dropwizard framework and I want to use it to package my existing REST service.
In the tutorial I noticed that the response content type is not set using a ResponseBuilder, can I set the reponse type like I would do for a regular REST service if it were not in a Dropwizard framework ?
The reason I want to set a dynamic response content type is because the webservice does not know the kind of data it is serving.
Thanks
You should be able to just return a Response object and adjust the type. For instance:
#Path("/hello")
#Produces(MediaType.TEXT_PLAIN)
public class Example{
#GET
public Response sayHello() {
return Response.ok("Hello world").type(MediaType.TEXT_HTML).build();
}
}

Jersey: Is there a clean way to specify allowed URL extensions?

I'm using Jersey 1.17.1 and on every URL I've created I want to allow people to put ".json" at the end or not. Here's an example of what I've done:
#GET
#Path("basepath{extension: (\\.json)?}")
public String foobar() {
...
}
Eventually I'm going to let them choose between nothing, ".json" or ".xml" and I'm concerned about my DRY violation here. I'll have to change every #Path to this instead:
#GET
#Path("basepath{extension: (\\.json|\\.xml)?}")
public String foobar() {
...
}
Is there a better way to do this that lets my path value be more reusable? Although I can't use Jersey 2.0, I'd be interested to know if it can solve this problem.
One way to do this is to subclass PackagesResourceConfig and inform Jersey which extensions should map to which media types. For instance:
public class ExampleResourceConfig extends PackagesResourceConfig {
#Override
public Map<String, MediaType> getMediaTypeMappings() {
Map<String, MediaType> map = new HashMap<>();
map.put("xml", MediaType.APPLICATION_XML_TYPE);
map.put("json", MediaType.APPLICATION_JSON_TYPE);
return map;
}
}
and then your actual REST service might look like:
#GET
#Path("basepath")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response foobar() {
...
}
Jersey will select the appropriate media type based on the url extension. Note that Response is returned instead of String. I'm not sure how you're building your response and what your requirements are but Jersey can handle converting your Java beans into either XML or JSON (or even JSONP) without a problem.
In the REST API implementation , the resource representation can be either xml or json or etc. This is not a good way of restful implementation if you specify the types as the extensions of the URL. The correct way is to use HTTP ACCEPT header
like Accept: application/json or
Accept: application/xml
Refer : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

How to access parameters in a RESTful POST method

My POST method looks like this:
#POST
#Consumes({"application/json"})
#Path("create/")
public void create(String param1, String param2){
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
}
When I create a Jersey Client in Netbeans the method who calls the post method looks like this:
public void create(Object requestEntity){
webResource.path("create").type(MediaType.APPLICATION_JSON).post(requestEntity);
}
When running this test:
#Test
public void hello(){
String json = "{param1=\"hello\",param2=\"hello2\"}";
this.client.create(json);
}
It gives the following output in the server:
INFO: param1 = {param1="hello",param2="hello2"}
INFO: param2 =
What do I need to change so that the parameters are giving the correct value?
Your #POST method should be accepting a JSON object instead of a string. Jersey uses JAXB to support marshaling and unmarshaling JSON objects (see the jersey docs for details). Create a class like:
#XmlRootElement
public class MyJaxBean {
#XmlElement public String param1;
#XmlElement public String param2;
}
Then your #POST method would look like the following:
#POST #Consumes("application/json")
#Path("/create")
public void create(final MyJaxBean input) {
System.out.println("param1 = " + input.param1);
System.out.println("param2 = " + input.param2);
}
This method expects to receive JSON object as the body of the HTTP POST. JAX-RS passes the content body of the HTTP message as an unannotated parameter -- input in this case. The actual message would look something like:
POST /create HTTP/1.1
Content-Type: application/json
Content-Length: 35
Host: www.example.com
{"param1":"hello","param2":"world"}
Using JSON in this way is quite common for obvious reasons. However, if you are generating or consuming it in something other than JavaScript, then you do have to be careful to properly escape the data. In JAX-RS, you would use a MessageBodyReader and MessageBodyWriter to implement this. I believe that Jersey already has implementations for the required types (e.g., Java primitives and JAXB wrapped classes) as well as for JSON. JAX-RS supports a number of other methods for passing data. These don't require the creation of a new class since the data is passed using simple argument passing.
HTML <FORM>
The parameters would be annotated using #FormParam:
#POST
#Path("/create")
public void create(#FormParam("param1") String param1,
#FormParam("param2") String param2) {
...
}
The browser will encode the form using "application/x-www-form-urlencoded". The JAX-RS runtime will take care of decoding the body and passing it to the method. Here's what you should see on the wire:
POST /create HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 25
param1=hello&param2=world
The content is URL encoded in this case.
If you do not know the names of the FormParam's you can do the following:
#POST #Consumes("application/x-www-form-urlencoded")
#Path("/create")
public void create(final MultivaluedMap<String, String> formParams) {
...
}
HTTP Headers
You can using the #HeaderParam annotation if you want to pass parameters via HTTP headers:
#POST
#Path("/create")
public void create(#HeaderParam("param1") String param1,
#HeaderParam("param2") String param2) {
...
}
Here's what the HTTP message would look like. Note that this POST does not have a body.
POST /create HTTP/1.1
Content-Length: 0
Host: www.example.com
param1: hello
param2: world
I wouldn't use this method for generalized parameter passing. It is really handy if you need to access the value of a particular HTTP header though.
HTTP Query Parameters
This method is primarily used with HTTP GETs but it is equally applicable to POSTs. It uses the #QueryParam annotation.
#POST
#Path("/create")
public void create(#QueryParam("param1") String param1,
#QueryParam("param2") String param2) {
...
}
Like the previous technique, passing parameters via the query string does not require a message body. Here's the HTTP message:
POST /create?param1=hello&param2=world HTTP/1.1
Content-Length: 0
Host: www.example.com
You do have to be particularly careful to properly encode query parameters on the client side. Using query parameters can be problematic due to URL length restrictions enforced by some proxies as well as problems associated with encoding them.
HTTP Path Parameters
Path parameters are similar to query parameters except that they are embedded in the HTTP resource path. This method seems to be in favor today. There are impacts with respect to HTTP caching since the path is what really defines the HTTP resource. The code looks a little different than the others since the #Path annotation is modified and it uses #PathParam:
#POST
#Path("/create/{param1}/{param2}")
public void create(#PathParam("param1") String param1,
#PathParam("param2") String param2) {
...
}
The message is similar to the query parameter version except that the names of the parameters are not included anywhere in the message.
POST /create/hello/world HTTP/1.1
Content-Length: 0
Host: www.example.com
This method shares the same encoding woes that the query parameter version. Path segments are encoded differently so you do have to be careful there as well.
As you can see, there are pros and cons to each method. The choice is usually decided by your clients. If you are serving FORM-based HTML pages, then use #FormParam. If your clients are JavaScript+HTML5-based, then you will probably want to use JAXB-based serialization and JSON objects. The MessageBodyReader/Writer implementations should take care of the necessary escaping for you so that is one fewer thing that can go wrong. If your client is Java based but does not have a good XML processor (e.g., Android), then I would probably use FORM encoding since a content body is easier to generate and encode properly than URLs are. Hopefully this mini-wiki entry sheds some light on the various methods that JAX-RS supports.
Note: in the interest of full disclosure, I haven't actually used this feature of Jersey yet. We were tinkering with it since we have a number of JAXB+JAX-RS applications deployed and are moving into the mobile client space. JSON is a much better fit that XML on HTML5 or jQuery-based solutions.

Categories

Resources