views:

4737

answers:

3

Goal

Java client for Yahoo's HotJobs Resumé Search REST API.

Background

I'm used to writing web-service clients for SOAP APIs, where wsimport generates proxy stubs and you're off and running. But this is a REST API, which is new to me.

Details

Progress

I looked at question Rest clients for Java?, but the automated solutions there assume you are providing both the server and the client, with JAXB invoked on POJOs to generate a schema and a REST API.

Using Jersey (a JAX-RS implementation), I have been able to make a manual HTTP request:

import com.sun.jersey.api.client.*;

...

ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);

WebResource webResource = client.resource("https://hj.yahooapis.com/v1/HJAuthTokens");
webResource.accept("application/xml");

// body is a hard-coded string, with replacements for the variable bits
String response = webResource.post(String.class, body);

// parse response into a org.w3c.dom.Document
// interface with Document via XPATH, or write my own POJO mappings

The response can look like:

<?xml version="1.0" encoding="utf-8"?>   
<Response>   
    <ResponseCode>0</ResponseCode>   
    <ResponseMessage>Login successful</ResponseMessage>
    <Token>NTlEMTdFNjk3Qjg4NUJBNDA3MkJFOTI3NzJEMTdDNDU7bG9jYWxob3N0LmVnbGJwLmNvcnAueWFob28uY29tO0pVNWpzRGRhN3VhSS4yQVRqRi4wWE5jTWl0RHVVYzQyX3luYWd1TjIxaGx6U0lhTXN3LS07NjY2MzM1OzIzNDY3NTsxMjA5MDE2OTE5OzZCM1RBMVNudHdLbl9VdFFKMFEydWctLQ==</Token>   
</Response>

Or, it can look like:

<?xml version="1.0" encoding="utf-8"?>   
<yahoo:error xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" xml:lang="en-US">   
    <yahoo:description>description</yahoo:description>   
    <yahoo:detail>   
        <ErrorCode>errorCode</ErrorCode>   
    </yahoo:detail>   
</yahoo:error>

Questions

  • Is there a way to auto-generate POJOs which can be marshalled/unmarshalled without a formal schema?
  • Should I attempt to generate those POJOs by hand, with JAXB annotations?
  • Is there some tool I should be leveraging so I don't have to do all this manually?
+1  A: 

It's interesting that they provide an HTTP URL as the namespace URI for the schema, but don't actually save their schema there. That could be an oversight on their part, which an email or discussion-list posting could correct.

One approach is to create your own schema, but this seems like a lot of work for little return. Given how simple the messages are, I wonder if you even need a POJO to wrap them? Why not just have a handler that extracts the data you need using XPath?


Edit: blast from the past, but I saw the comment, reread the question, and realized that the first sentence was hard to understand. So, clarification:

One very good habit, if you're going to write a publicly accessible web service, is to make your schema document available at the same URL that you use for the schema's namespace URI -- or better, have that URL be a link to complete documentation (the W3C XSD namespace is itself a good example: http://www.w3.org/2001/XMLSchema).

kdgregory
I'm writing their API support to see if there is indeed a schema. XPath just seems like a brittle solution; how do I know there are not novel XML packets that my XPath won't handle?
Chase Seibert
How will you handle any new elements if you don't know what they are regardless of the technology? If you assume some version sanity (i.e. they'll structure their data for reasonable compatibility in that your XPath will still work), how does that not solve the problem?
Will Hartung
I ended up using XML Spy to generate a schema from the example packets, then I generated mappings for those using JAXB. Several times I had to add new schema to the example packets, and then regenerate the schema and JAXB bindings.
Chase Seibert
+1  A: 

I would suggest writing beans by hand, and only annotating with JAXB annotations if you have to. For most accessors/mutators (getters/setters) you do not have to; by default all public bean accessors and fields are considered, name is derived using bean convention, and default is to use elements instead of attributes (so attributes need to be annotated).

Alternatively you can of course write schema by hand, generate beans using JAXB, if you like W3C Schema a lot. And just use resulting code, not schema, for data binding.

As to POJO: that can be very simple. Something like:

@XmlRootElement("Response")
class Response {
  public int responseCode;
  public String responseMessage;
  public String token; // or perhaps byte[] works for automated base64?
}

and similarly for other ones. Or, use getters/setters if you like them and don't mind bit more verbosity. These are just data containers, no need to get too fancy.

And if you must auto-detect type from content, consider using Stax parser to see what the root element, and then bind using JAXB Unmarshaller, handing XMLStreamReader that points to that root element. That way you can pass different object type to bind to.

And finally: sending/receiving requests: plain old HttpURLConnection works ok for GET and POST requests (construct using, say, URL.openConnection()). Jakarta HttpClient has more features if need be. So oftentimes you don't really need a separate REST client -- they may come in handy, but generally build on simple http client pieces.

StaxMan
+1  A: 

I find HTTP4E very useful for making REST calls. It is an awesome Eclipse plugin, it has tabs, syntax coloring, auto suggest, code generation, REST HTTP call replay, etc.. It does a great job of HTTP debugging, HTTP tampering, hacking. I am having so much fun with it.

http://http4e.roussev.org/