Please forgive me if any of this is wrong -I’m completely new to Java. My task is to set up the client/server architecture for an upcoming Facebook game. On the server-side, I have:
- Java
- Tomcat
- RestEasy
- BlazeDS
- Enunciate
All held together with Maven. I can annotate RESTful endpoints with @Path() and they will spit out objects serialized in AMF when I hit them in the browser. So far so good. Now I need to consume these endpoints on the client/Flex-side. Enunciate has generated AS files for the types I have annotated with @XmlRootElement in Java, and I can use these types in my AS3 code. The problem is that hitting REST endpoints in AS3 is pretty ugly. It looks something like this:
function resourceRetrieved(event:Event):void {
var stream:URLStream = URLStream( event.target );
var resource:SomeJavaClass = ( stream.readObject() as SomeJavaClass );
lblResult.text = resource.message;
}
var request:URLRequest = new URLRequest("http://localhost:8080/rest/somefunc");
request.method = URLRequestMethod.GET;
var variables:URLVariables = new URLVariables();
variables.message = "This is my test string!";
request.data = variables;
var resourceStream:URLStream = new URLStream();
resourceStream.addEventListener("complete", resourceRetrieved)
resourceStream.load(request);
Ugly -and I have to write this by hand in order to get the benefits of strong typing. However! I noticed when digging through the source code that if the @WebService and @WebMethod tags are used instead of @Path, wonderful strongly-typed AS3 wrappers for my service classes are generated by Enunciate, along with corresponding AS3 events. It also generates the correct services-config.xml! The usage then becomes something like this:
function onSomeFuncEvent(event:SomeJavaServiceEvent):void {
lblResult.text = event.result;
}
var service:SomeJavaService = new SomeJavaService();
service.addEventListener( SomeJavaServiceEvent.SomeFuncEvent, onSomeFuncEvent );
service.someFunc("This is my test string!");
As you can see, the consumer of the generated code does not need to know where the endpoint is, what types are returned from the events, etc. I would like to go this route because I believe it will be easier to maintain. That brings me to my questions:
- Why are the wonderful Service and ServiceEvent objects only generated for @WebService and @WebMethod (which the Internet tells me is JAX-WS) but not @Path? Is it work that hasn’t been done, or work that can not be done given the spec differences between JAX-RS and JAX-WS? (I see that the as3-endpoint.fmt is specifically only applied to @WebService in the code)
- Am I wrong in wanting to use REST here? The Java/Tomcat/RestEasy/BlazeDS stack was recommended by my CTO but it seems to me (after fiddling for a day or two) that BlazeDS/Flex don’t get along that well with REST.
- Is there a Java->AMF->Flex stack I should be considering?
Thank you for your time, and again I am sorry if these are obvious issues. My background is in game development, not web development.
It’s work that could be done, but hasn’t yet. And there’s an unanswered question of whether it should be done.
REST is hard. Service-oriented APIs (e.g. SOAP, AMF) are much more intuitive to developers. JAX-RS has made creating REST APIs easy to do, but at the cost of giving developers more rope to hang themselves with. More specifically, JAX-RS makes it easy to create HTTP-based APIs, but just because it’s using HTTP doesn’t make it REST. For a better understanding of what I’m talking about I’d suggest Martin Fowler’s essay on the Richardson Maturity Model:
http://martinfowler.com/articles/richardsonMaturityModel.html
So there’s a lot more to REST than just making an HTTP request and parsing the response. By extension, there is a lot more to creating a client-side service that calls a JAX-RS resource (i.e. @Path) than just wrapping HTTP calls in a convenient AMF service class. Cacheing, layering, HATEOAS, etc., etc., all come into play and would have to be “hidden” in a client-side service generated by Enunciate.
You’re not wrong but it appears that you might be underestimating what it means to “use REST”. So IMO, you’ve got two options:
Perhaps. At least one thing is for sure: the designers of BlazeDS/AMF weren’t thinking REST when they designed their stack.
BlazeDS and GraniteDS are the only two I can think of. They’re both good IMO, so just take your pick.