Dropwizard Multiple Rest API versions - java

Currently I am designing how to deal with routing in a versioned rest API where the version is not part of the url, but sent via a header variable.
I have considered/seen things like:
Re-writing the url based on the header variable i.e. the request /orders {X-Media-Type: v1} would rewrite to /v1/orders and then we could have a #Path("/v1/orders") OrderV1Resource {} and thus making v2 would be trivial #Path("/v2/orders") OrderV2Resource {}. (my first preference) How to use a servlet filter in Java to change an incoming servlet request url?
Having a Single #Path("/orders") OrderResource {} where each of it's methods have an injected HeaderParam and I could check the header variable and then decide which Order API implementation I wanted to use (which seems very messy to me)
// pseudo-java code
#Path("/orders")
OrderResource {
OrderV1Impl v1Impl;
OrderV2Impl v2Impl;
#GET
public List<Order> findAll(#HeaderParam header) {
version = header.get("accepts")
if(version.equals("v1")) { return v1Impl.findAll() }
else if(version.equals("v2")) { return v2Impl.findAll() }
return error
}
}
Or just bundling them up in seperated JARS and having a service look at the header and route to the correct version. (seems to make sense if the app grows to be really large)

I ended up passing the version in via a header then used this to route the desired resource via a javax.servlet.Filter.
Example Accept header:
Accept: application/vnd.datarank.v1+json

Related

Designing API to start and stop a process with Jersey

I am developing a REST web server with Java and Jersey. This is my first web application and I want to be sure that I am structuring the application well. I created my first function which is working well:
#Path("/startAuto")
public class Rest {
#GET
public String startAuto() {
try {
ProcessBuilder pb = new ProcessBuilder("/startAuto.sh");
Process p = pb.start();
p.waitFor();
return ("Auto Started");
} catch (Exception e) {
e.printStackTrace();
return ("error");
}
}
}
I want to add a new function like stopAuto.
Which is cleaner: adding the function in this class or create a new class?
Approach 1
The GET method should be used for retrieving information. Don't use GET to change a state of a resource. Prefer POST instead.
So, you'll have something as following:
Start the process:
POST /auto/start HTTP/1.1
Host: example.org
Stop the process:
POST /auto/stop HTTP/1.1
Host: example.org
With this approach, you will have the following in your resource class:
#Path("/auto")
public class Rest {
#POST
#Path("/start")
public String start() {
...
}
#POST
#Path("/stop")
public String stop() {
...
}
}
Approach 2
REST is protocol independent and is a resource-oriented architecture. When implementing REST applications over the HTTP protocol, for example, the resource is identified by the URI and the operation over the resource is expressed by the HTTP method.
With this approach, the new state of the resource will be expressed in the request payload using JSON, for example. To obtain the state of a resource, use GET and to replace the state of a resource, use PUT.
You could have the following:
Start the process:
PUT /auto/status HTTP/1.1
Host: example.org
Content-Type: application/json
{
"value" : "started"
}
Stop the process:
PUT /auto/status HTTP/1.1
Host: example.org
Content-Type: application/json
{
"value" : "stopped"
}
Get the status of the process:
GET /auto/status HTTP/1.1
Host: example.org
Your resource class will be like:
#Path("/auto/status")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class Rest {
#PUT
public String changeStatus(Status status) {
...
}
#GET
public Status getStatus() {
...
}
}
And that's what the Status class will look like:
public class Status {
private String value;
// Default constructor, getters and setters omitted
}
Response status codes
You certainly will need to inform your client about the result of the operation. To do it, use the HTTP response status codes.
A few status that might be useful:
200: Use this status to indicate that the request has succeeded.
202: Use this status code to indicate the request has been accepted for processing, but the processing has not been completed.
204: Use this status code to indicate the server has successfully fulfilled the request and that there is no additional content to send in the response payload body.
409: Use this indicates that the request could not be completed due to a conflict with the current state of the target resource.
As peeskillet points out in his comment, it depends on how you want to structure your URLS
If you wanted something like
/auto/start and
/auto/stop
I would go for all in one class structured as follows
#Path("/auto")
public class Rest {
#GET
#Path("/start")
public String startAuto() {
}
#GET
#Path("/stop")
public String stopAuto() {
}
}
Good structure is essential to any good project/product, however it is also a question whose answers vary from situation to situation.
However, if in doubt, a good starting point is to group your endpoints as per "responsibilities". If they belong together, then put them in the same class.
Personal Opinion : Boundary-Control-Entity is the simplest starting point that I could find for starting a project. The structure then adapts as per need. Take a look at this article from Adam Bien for more ideas.
Generally it is better to put another function related with the current resource into the same class.
But you should also remember that REST operates with resources but not with functions (nouns but not verbs). So probably it makes sense to make your API more RESTfull:
You target resource this is an auto. So it could be accessible by the URL "/auto"
Functions "start" and "stop" is used to change the state of resource. So it means that you have a "sub-resource" of the auto that could be accessed by URL "/auto/state" with possible values, for instance "started", "stopped". This values is accessible by GET:/auto/state
Now it is possible to change the state with a REST style using PUT/POST request with a status value in the body (also it is possible to use PATCH method in order to partially update auto). Probably, at your case, it makes sense to leave only one method exposed as an endpoint which consumes status value and call logic for starting or stopping the auto in accordance with parameter.

Best practices for method types in JAX-RS

What are the best practices regarding the method types in JAX-RS ?
I am interested in the following methods: GET, POST, PUT and DELETE.
My possible approaches:
GET - always return a response.
#GET
#Path("/path/{something}")
public T getT() {
...
return t; // t - instance of T
}
POST
#POST
#Path("/path")
public T/void createOrUpdate() {
...
return t; // t - instance of T
}
Q: Is it better to return the entire created resource or just an "ACK response" or to have a void method? What about a POST that is used as GET (when we want to avoid the URL length limitation)?
PUT
#PUT
#Path("/path")
public T/void createOrUpdate() {
...
return t; // t - instance of T
}
Q: Is it better to have a void method or a response for the created/updated resource or different responses for creation / update or just an ACK response ?
DELETE
#DELETE
#Path("/path/{something}")
public T/void deleteT() {
...
return t; // t - instance of T
}
Q: Is is better to have a void method or to return the deleted resource or to return an ACK response ?
Is it ok to always have T = javax.ws.rs.core.Response (when T is used)?
I saw that:
Lars Vogel uses GET - T, POST - void, PUT - T, DELETE - void
Oracle uses GET - T, POST - T/void, DELETE - void
JAX-RS is a specification for developing RESTful Web Services with Java. There is a reference implementation that is included in Java EE but since it is a specification, other frameworks can be written to implement the spec, and that includes Jersey, Resteasy, and others.
JAX-RS as such does not lay down any guidelines on the return types and response codes for the REST API's. However, there are a few guidelines (these are not hard and fast rules) in the REST standard which you might want to follow:
Method GET
Successful Response RETURN the resource with 200 OK
Failure Response RETURN appropriate response code
Method POST
Successful Response RETURN the link to the newly created resource in Location response header with 201 status code
Failure Response RETURN appropriate response code
Method PUT
Successful Response RETURN the updated resource representation with 200 OK or return nothing with 204 status code
Failure Response RETURN appropriate response code
Method DELETE
Successful Response RETURN nothing with 200 or 204 status code
Failure Response RETURN appropriate response code
In practice, POST works well for creating resources. The URL of the newly created resource should be returned in the Location response header. PUT should be used for updating a resource completely. Please understand that these are the best practices when designing a RESTful API. HTTP specification as such does not restrict using PUT/POST with a few restrictions for creating/updating resources. Take a look at Twitter REST API best practices that summarizes the best practices for RESTful API's.
This answer is not correct/up to date. Please check #ROMANIA_engineer answer instead.
You should never return void. The best practice is to always return a javax.ws.rs.core.Response. But note that even if you define the webresource with void, your server will return a HTTP response.
On POST and PUT, it may be better to return the modified resource, including its id. Some front-end framework and/or middleware will use it to synchronise the resource with your server (as instance, see Backbone Model).
On DELETE, it depends of the action you try to achieve.. But usually an ACK is enough.
NB : Anyway, whatever you return, don't forget to respect your security policies !
Response #Atul : When you send HTTP Request from client or HTTP Response from your server, some data may be protected. As instances :
On user update (username, password, or anything else) do not return the user password in the HTTP Response.
When user log in, you better use a HTTPS protocol and never send the password in plaintext
.. etc
I give it a shot and state a "no there is no best practice". This because the underlying protocol (HTTP) actually has return values (such as 200-OK, 500-Internal Error...) in any case unless a broken connection which should be followed by your service as well.
Since you are not implementing the HTTP-Protocol but a own-designed service following its own rules, no there is no best practice, you will have to define "your protocol" in a way it matches your day to day business the best.
For example when it comes to your delete operation a caller could either not be interested in a response at all or as well expect you to work like a stack and return him the "deleted/removed" element on call. It is up to you to know what fits your needs best.

Jersey web service proxy

I am trying to implement a web service that proxies another service that I want to hide from external users of the API. Basically I want to play the middle man to have ability to add functionality to the hidden api which is solr.
I have to following code:
#POST
#Path("/update/{collection}")
public Response update(#PathParam("collection") String collection,
#Context Request request) {
//extract URL params
//update URL to target internal web service
//put body from incoming request to outgoing request
//send request and relay response back to original requestor
}
I know that I need to rewrite the URL to point to the internally available service adding the parameters coming from either the URL or the body.
This is where I am confused how can I access the original request body and pass it to the internal web service without having to unmarshall the content? Request object does not seem to give me the methods to performs those actions.
I am looking for Objects I should be using with potential methods that would help me. I would also like to get some documentation if someone knows any I have not really found anything targeting similar or portable behaviour.
Per section 4.2.4 of the JSR-311 spec, all JAX-RS implementations must provide access to the request body as byte[], String, or InputStream.
You can use UriInfo to get information on the query parameters. It would look something like this:
#POST
#Path("/update/{collection}")
public Response update(#PathParam("collection") String collection, #Context UriInfo info, InputStream inputStream)
{
String fullPath = info.getAbsolutePath().toASCIIString();
System.out.println("full request path: " + fullPath);
// query params are also available from a map. query params can be repeated,
// so the Map values are actually Lists. getFirst is a convenience method
// to get the value of the first occurrence of a given query param
String foo = info.getQueryParameters().getFirst("bar");
// do the rewrite...
String newURL = SomeOtherClass.rewrite(fullPath);
// the InputStream will have the body of the request. use your favorite
// HTTP client to make the request to Solr.
String solrResponse = SomeHttpLibrary.post(newURL, inputStream);
// send the response back to the client
return Response.ok(solrResponse).build();
One other thought. It looks like you're simply rewriting the requests and passing through to Solr. There are a few others ways that you could do this.
If you happen to have a web server in front of your Java app server or Servlet container, you could potentially accomplish your task without writing any Java code. Unless the rewrite conditions were extremely complex, my personal preference would be to try doing this with Apache mod_proxy and mod_rewrite.
There are also libraries for Java available that will rewrite URLs after they hit the app server but before they reach your code. For instance, https://code.google.com/p/urlrewritefilter/. With something like that, you'd only need to write a very simple method that invoked Solr because the URL would be rewritten before it hits your REST resource. For the record, I haven't actually tried using that particular library with Jersey.
1/ for the question of the gateway taht will hide the database or index, I would rather use and endpoint that is configured with #Path({regex}) (instead of rebuilding a regexp analyser in your endpoint) .
Use this regex directly in the #path, this is a good practice.
Please take a look at another post that is close to this : #Path and regular expression (Jersey/REST)
for exemple you can have regexp like this one :
#Path("/user/{name : [a-zA-Z][a-zA-Z_0-9]}")
2/ Second point in order to process all the request from one endpoint, you will need to have a dynamic parameter. I would use a MultivaluedMap that gives you the possibility to add params to the request without modifying your endpoint :
#POST
#Path("/search")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces({"application/json"})
public Response search( MultivaluedMap<String, String> params ) {
// perform search operations
return search( params);
}
3/ My 3rd advice is Reuse : make economy and economy make fewer bugs.
it's such a pitty to rewrite a rest api in order to perform solr search. You can hide the params and the endpoint, but could be great to keep the solr uri Rest formatting of the params in order to reuse all the search logic of solr directly in your api. This will make you perform a great economy in code even if you hide your solr instance behind you REST GATEWAY SERVER.
in this case you can imagine :
1. receive a query in search gateway endpoint
2. Transform the query to add your params, controls...
3. execute the REST query on solr (behind your gateway).

How to deal with accept-parameters when developing a jax-rs application

In order to deal with different versions of a content-type i am trying to use the accept-parameters of the "Accept*" headers (RFC 2616).
Accept: application/vnd.mycompany.mytype;version=2 , application/vnd.mycompany.mytype;version=1;q=0.1
The problem is that Jax-RS annotations do not support Accept-parameters...
#GET
#Produces("application/vnd.test;version=1")
public Response test1() {
return Response.ok("Version 1", "application/vnd.test").build();
}
#GET
#Produces("application/vnd.test;version=2")
public Response test2() {
return Response.ok("Version 2", "application/vnd.test").build();
}
Results in a media type conflict exception:
Producing media type conflict. The resource methods public javax.ws.rs.core.Response test.resources.TestResource.test2() and public javax.ws.rs.core.Response test.resources.TestResource.test1() can produce the same media type
Maybe, this exception only related to my JAX-RS framework (Jersey), but i'm afraid this is due to the JSR311 which is not explicit about accept-parameters.
By now, i'm using content-types which holds the version within their names, but i found this solution pretty uggly.
#GET
#Produces("application/vnd.test-v1")
public Response test() {
return Response.ok("Version 1", "application/vnd.test-v1").build();
}
Do you have any ideas about how to deal with accept-parameters ?
EDIT
I think i wasn't clear enough.
I want to automatically route the request to specific methods.
These methods are versioned and correspond to a specific version of the returned content-type.
JAX-RS current implementation prevents me to use accept-parameters to route the request (to the corresponding method).
greenkode suggest that i manage the version accept-parameter within a dispatching method (using #HeaderParam("Accept")).
This solution would end-up in re-writing the content negociation logic which is embeded in the framework (and described in JSR 311).
What can i do to use both accept-parameter and content-negociation logic from JAX-RS ?
Maybe a solution is to use another framework (I only worked with Jersey by Now). But i don't know which one.
The JAX-RS specification does not explicitly state anything about ignoring Accept header parameters. But the only parameter for which handling is definitely defined is quality (q). This is a possible area for improvement as it seems to have lead to ambiguity (or outright bugginess) in the Jersey implementation. The current version of Jersey (1.17) does not take Accept header parameters into consideration when matching incoming requests to resource methods, which is why you are getting the error:
SEVERE: Producing media type conflict. The resource methods ...
For the resource:
#GET
#Produces("application/vnd.test;version=1")
public Response test1() {
return Response.ok("Version 1", "application/vnd.test").build();
}
#GET
#Produces("application/vnd.test;version=2")
public Response test2() {
return Response.ok("Version 2", "application/vnd.test").build();
}
It would appear that Jersey performs a 'uniqueness' check based on the Accept header 'type/subtype', totally omitting any parameters. This can be confirmed by testing with various pairs of headers on the 'matching' resource methods:
Resource 1 Resource 2
----------------------------------------
text/html;q=0.4 text/html;q=0.8
text/html text/html;q=0.2
text/html text/html;qs=1.4
text/html;qs=1.4 text/html;qs=1.8
text/html;level=1 text/html;level=2
text/html;foo=bleh text/html;bar=23
All fail with the same error. If the assumption were made that only the quality parameter is ever sent, then it would make sense to only match on 'type/subtype', because this kind of request is nonsensical:
Accept: text/html;q=0.8, text/html;q=0.4, text/html
Aka, quality parameters only make sense when you are dealing with a mix of possible content types. However, this sort of limited matching fails when non-quality parameters or additional parameters are being sent:
Accept: text/html;version=4.0;q=0.8, text/html;version=3.2;q=0.4
So what are the possible solutions?
Intercept the high level request based off 'type/subtype', then route to more appropriate method (you've indicated you do not want to do this)
Modify your expected headers. For example 'application/vnd.mycompany.mytype+v2' and 'application/vnd.mycompany.mytype+v1'. No other changes would be required and you could keep on using Jersey
Switch frameworks. RESTEasy happens to handle your scenario with ease.
With RESTEasy, and resource:
#Path("/content/version")
public class ContentVersionResource {
#GET
#Produces("application/vnd.test;version=1")
public Response test1() {
return Response.ok("Version 1", "application/vnd.test").build();
}
#GET
#Produces("application/vnd.test;version=2")
public Response test2() {
return Response.ok("Version 2", "application/vnd.test").build();
}
}
A successful match is made with the following Accept header:
Accept: application/vnd.test;version=1;q=0.3, application/vnd.test;version=2;q=0.5
Response: Version 2
And this:
Accept: application/vnd.test;version=1;q=0.5, application/vnd.test;version=2;q=0.3
Response: Version 1
You can download and test with this sample project. Git, Maven and JBoss 7.x required
Unless I'm missing something. JAX-RS does support Accept parameters. look at the #Consumes("*/*") annotation. Also, The exception you're getting with media type conflict occurs because you have two GET methods at the same url. annotate the test2() method with #Path("test2"), then send your GET request to url/test2 instead. that should get rid of that error.
EDIT
You can inject the Value of the Accept header using #HeaderParams. Here's a sample of what I did.
#Path("/conneg")
public class ConnNeg {
#GET
#Produces("application/vnd.test;version=1")
public Response test1(#HeaderParam("Accept") String header) {
System.out.println(header);
return Response.ok("Version 1", "application/vnd.test").build();
}
}
passing the request
Accept: application/vnd.test;version=2 , application/vnd.test;version=1;q=0.1
this will print
application/vnd.test;version=2 , application/vnd.test;version=1;q=0.1
You can then handle it manually. Is this what you're looking for?
With Jersey framework, the Accept header of the HTTP request declared what is most acceptable. If a resource class is capable of producing more that one MIME media type then the resource method chosen will correspond to the most acceptable media type as declared by the client.
In your case, if the accept header is
Accept: application/vnd.mycompany.mytype;version=2
then the method test1() will be invoked.
If it is
Accept: application/vnd.mycompany.mytype;q=0.9 version=2, application/vnd.mycompany.mytype;version=1
the latter one will be called.
More than one media type may be declared in the same #Produces declaration, for example:
#GET
#Produces({"application/vnd.mycompany.mytype; version=2", "application/vnd.mycompany.mytype; version=1"})
public Response test() {
return Response.ok("").build();
}
the test(9 method will be called if either of the 2 mediatypes is acceptable. if both are acceptable, the first will be invoked.
Hope it helps!

Apache CXF: Forwarding an information from an interceptor to the actual webservice implementation

I'm running a JAX-WS web service which is based on Apache CXF 2.3.1 on a JBoss6 server.
My service offers a function getWeight. This function should return the values in different units (kilos, pounds) depending on an additional information within the SOAP header. For that purpose I have added my own interceptor:
public class MySoapHeaderInterceptor extends AbstractSoapInterceptor
{
public MySoapHeaderInterceptor()
{
super(Phase.USER_PROTOCOL);
}
...
}
The intercepting works fine and I can parse the additional element from the SOAP header and can set up a variable based on this element:
boolean poundsRequested = true;
Now my problem occurs. I don't know how to forward the variable poundsRequested to my actual WebService implementation MyServiceImpl. This class is calling another class ValueReader where I finally need the information from the SOAP header.
I've already tried to set up a global static variable ValueReader.poundsRequested. But such a solution is not thread safe. It might happen that the calls of two clients interfere, and can overwrite each others set up variable.
To sum up: I basically need a possibility to forward a variable from an Apache CXF Interceptor to the actual webservice implementation. Moreover the value of this variable needs to be unique for each request.
In the interceptor, you can save the values that you need on the incoming message:
message.put("my.value", value);
Inside your implementation, you can do one of two things:
1) Have the standard JAXWS WebServiceContext injected via an #Resource thing and call
context.getMessageContext().get("my.value");
2) Since you are tied to CXF anyway, do:
PhaseInterceptorChain.getCurrentMessage().get("my.value");
Ideally, the format in which the weights are requested should be a part of your payload - it does not make sense for it to be a header.
You may not need an interceptor for getting hold of this header, if you are using JAX-WS(recommended with CXF), you can get to this using #WebParam annotation with header attribute set to true.

Categories