I'm at the beginning of creating a Webservice with Java.
I want to POST a XML-Request to a Restful Webservice and the Response should be a modified XML. So actually just the Root-Element of the Request should be changed and it should be added another element.
Request:
<Request>
<name>name</name>
</Request>
Response:
<Response>
<name>name</name>
<status>created</status>
</Response>
Currently I'm only returning the Request.
Which is the best/easiest way to modify the Request? Can I do it with JAXB?
public class Resource {
#POST
#Produces
#Consumes
public Request request(Request r) {
return r;
}
}
It seems you are using Jersey to expose the rest api. As RedFive mentioned there are plenty of examples available to build rest api using jersey(jax-rs implementation) on internet. I did a small POC while learning jersey. You can find a sample POST API implementation here. I am passing request bean(as Person class object). The request json/xml is unmarshalled to Person object. Instead of returning object of Request type, you have to return Response object. Hope this example helps you in learning jersey.
#POST
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response makeRequest(Request req) {
Response res = new Response();
res.setName(req.getName());
return Response.entity(res).status(Response.Status.CREATED).build();
}
One thing I want to point out that you may not return the status in the response body. You return 201(CREATED) http status code which resembles the same thing.
Related
I'm trying to create a Rest Api using Jax-rs Jersey from a base code generated by swagger.
The specifications are for exemple for a specific Request :
Code : 200
Description : User token for login
Schema : String
My problem is that the generated code use the class :javax.ws.rs.core.Response that should not be extended according to the documentation.
I'm using this kind of code to build the response :
return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK,apiToken)).build();
The response generated looks like that :
{"code":4,"type":"ok","message":"uHN2cE7REfZz1pD17ITa"}
When i only want to have :"uHN2cE7REfZz1pD17ITa" in the body. Is that possible using Jersey ? Or is this format part of the jax-rs specifications ?
Thank you.
ApiResponseMessage from Swagger does not extend Response from JAX-RS. Check the code and you will see that ApiResponseMessage is just a POJO. That is, the piece of code you posted in your question is just fine.
If you only need the token, you can use:
return Response.ok(apiToken).build();
The following gives you the same result:
return Response.ok().entity(apiToken).build();
Since your resource method will produce just a piece of text (not a valid JSON unless the piece of text is wrapped into quotes), the most suitable media type for the response would be text/plain. It could be achieved by either annotating the resource method with #Produces(MediaType.TEXT_PLAIN) or setting the media type in the response, as following:
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response getToken() {
String apiToken = ...
return Response.ok(apiToken).build();
}
#GET
public Response getToken() {
String apiToken = ...
return Response.ok(apiToken, MediaType.TEXT_PLAIN).build();
}
Alternatively you also could make your method return just a String:
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getToken() {
String apiToken = ...
return apiToken;
}
JAX-RS does not require Request or Response in specific format for text,json, xml, or html fallowing a schema . But They all have to be well formated in according to their specifications.
You can send text response like this in jersey
like this
return Response.ok().entity("uHN2cE7REfZz1pD17ITa").build();
I am new to swagger myself So i don't know if the Response in question can be changed or not . But There is no restriction from jersey side
I have 2 methods in my Java Rest resource file with same #Path uri but different #produces. The code below :
#GET
#Path("/messages")
#Produces(MediaType.APPLICATION_XML)
public List<Message> getAllMessages() {
return new ArrayList<Message>(service.getMessageMap().values());
}
#GET
#Path("/messages")
#Produces(MediaType.APPLICATION_JSON)
public List<Message> getAllMessagesJSON() {
return new ArrayList<Message>(service.getMessageMap().values());
}
when i test it with POSTMAN rest client i always get JSON output!!
Can some one explain why?? And if i want to get xml as well as json outputs, what to do??
I tried changing the content-type to application/xml..but i always get json!!
Content-Type is for the type of data being sent, either by the client as a request header or by the server as a response header. So you as a client sending the header is useless, as you are not sending any data. For the client, when it want to tell the server what type it wants, it uses the Accept: <media-type> header.
When there is no Accept header set, it usually defaults to */* leaving it up for grabs which method to pick in your case.
There seems to be many examples about creating RESTful clients by Jersey 1.x, but not Jersey 2.0 or above.
I referred to other questions and the Jersey's web site, but I still cannot create a client for REST due to the differences between Jersey 2.0 and the previous one.
So I'd like to ask some advice.
So far, my coding is like this.
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target("http://localhost:8080/CustomerBack2211/webresources/entities.customer");
Invocation.Builder invocationBuilder = target.request(MediaType.TEXT_XML_TYPE);
Response response = invocationBuilder.get();
System.out.println(response.getStatus());
System.out.println(response.readEntity(String.class));
This produces 406 error.
However, when I tried to test RESTful service by Glassfish server, the test works properly, and the server side class has its #GET methods having #Produces({"application/xml", "application/json"}).
So I don't see why the coding above produces 406 error on a Java application.
(i.e. the client side has #GET methods in the following way)
#GET
#Path("{id}")
#Produces({"application/xml", "application/json"})
public Customer find(#PathParam("id") Integer id) {
return super.find(id);
}
#GET
#Override
#Produces({ "application/xml"})
public List<Customer> findAll() {
return super.findAll();
}
Does any of you see what I'm doing wrong, or could you please suggest an example of a RESTful client?
Any advice will be helpful...thanks in advance!
In addition, I'd appreciate if you would offer information about how to invoke methods like GET, PUT and DELETE with appropriate parameters.
I just needed to put an ID number (i.e. integer values) when I was testing the server side class on Glassfish RESTful test. However, it seems that I need to set "Class" and/or "Entity" values as arguments, but I cannot see any information associated with them on the Jersey website.
For the first block of code:
406 means Not Acceptable.
Look at your request() method target.request(MediaType.TEXT_XML_TYPE). From the Javadoc of request() if states
Invocation.Builder request(MediaType... acceptedResponseTypes)
Start building a request to the targeted web resource and define the accepted response media types.
Invoking this method is identical to:
webTarget.request().accept(types);
So basically, in your request, you are saying that you will only Accept: text/plain. Now look at your resource methods. Look at the #Produces. None of them "produce" text/plain. It's all json or xml. That's why you get the exception. Change the accept to application/xml (or MediaType.APPLICATION_XML) on the client side, and you should no longer get this error.
For the second question: I'm assuming you mean why does it work when you test it from the browser.
If you send a request from the browser by simply typing in the url, it will send out the request with many Accept types. If you have firebug (for FireFox) or the developer tools (for Chrome), if you send out a request, you will see a header similar to
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
You can see application/xml in there. Even if application/xml wasn't there, the wild card */* is there, so basically almost all media types are acceptable as a return type when working in the browser.
For your last question:
Look at the API for SyncInvoker, which Invocation.Builder extends from. You will see different overrloaded put and post methods, most of which, as you mentioned accept an Entity.
There are a few different ways to build an Entity, all of which use one of the static methods. Here are some
Entity.entity( body, mediaType )
Entity.json( body )
Entity.xml( body )
And many more (see the Entity link above). But all of these static method return an Entity. So we could do something like
// resource method
#POST
#Consumes(MediaType.APPLICATION_XML)
public Response getResponse(Customer customer) { ... }
// some model class
#XmlRootElement
public class Customer { ... }
// client request
Customer customer = new Customer();
Response response = target.request().post(Entity.xml(customer));
Internally, the Customer will get converted to XML. If you used Entity.json is would get converted to JSON, BUT you need to make sure you have a JSON provider dependency. Jersey will not come with one by default. See more at Support for Common Media Type Representations
Also note, with your method find, when you try and make a request to the method, the request should end with an integer value, as that's the type specified for the {id} path parameter.
Let's say I have a Jersey JAX-RS api end-point for handling http://<some_path>/foo. Ignore the ....
#Path("foo")
public class FooResource
#GET
#Produces("application/json")
public response getMethod(...)
I want to create POST end-point for foo/{id}/bar, where id is a path parameter and there's a body associated with the HTTP POST.
Example: HTTP POST foo/1/bar with body: { data : "...." }.
How can I add this POST method within the FooResource class? I tried an inner class, but it didn't work when I tested with Postman.
#POST
#Path("{id}/bar")
#Produces("application/json")
public response myPostMethod(...)
You can have path at method level. This will have your post method accessible via /foo/{id}/bar
I have a webservice set up using CXF, JAX-RS and Spring. I have the following method:
#GET
#Path("/getPayload")
#Produces("application/XML")
public Response makePayload(){
Payload payload = new Payload();
payload.setUsersOnline(new Long(200));
return Response.ok().entity(payload).build();
}
How can I get access to the HttpRequest object in my makePayload()?
Will a call to this method generate a Session, and if so, can I get a handle to it and will that session be persistent for all subsequent requests from the same client?
#Context can be used to obtain contextual Java types related to the request or response:
#GET
#Path("/getPayload")
#Produces("application/XML")
public Response makePayload(#Context Request request) {
//...
}