Sunday 19 August 2012

Consuming .groovy files as runtime classes

Groovy has the ability to load .groovy files at runtime as normal class files, without the need to compile them first. This is how you do the same in a Java program. It took a bit of fiddling to get this to work, but this does the trick.



What this does is to create a Groovy Classloader that is configured to automatically compile all groovy files under "/base/directory/containing/groovy/files". If you then ask this Classloader for a class that exists as a normal class, it will provide it from it's parent. If however the class is actually written in an uncompiled .groovy file in that directory, it will also provide it having compiled the .groovy file automatically.


Friday 10 August 2012

REST APIs in Node.js. Part one - Routing

So, I'm playing with node.js again. In particular, I'm playing with writing a pure REST webapp. That is, a webapp where the client page is static HTML, Javascript and CSS and this communicates to the server using a pure REST API. This has a couple of big advantages - namely that all of the state is stored in the Javascript in the current page, and that different clients - such as native Android or iOS apps - can be written against the same API.

One of the things that a lot of people miss when they come to write REST APIs is that the links between resources are important. That is, you should be able to visit any resource and discover correct links to related resources from there. You should also be able to visit the base page and discover links into other parts of the app.

Now, part of the problem here is that people tend to use IDs instead of Links when they refer to other parts of the system. For example:

Note the author object has an ID as part of it. This means that a consumer of this resource needs to know how to write a URL to the Authors resources, using this ID as part of that URL, in order to look up the authors details. This is Bad™. What happens if the client doesn't know how to write the URLs? Or if the URLs change? Or numerous other things that might happen.

A better way of doing this would be:

Note that we now include a Link in the author object as well. The consumer simply needs to follow this link and they will be rewarded with the author details. This means that if the consumer doesn't know how to navigate the resources, it doesn't matter. And if the URLs change, it doesn't matter. It all still works.

Now for the problem. The majority of REST frameworks - at least the ones I've seen - don't easily cater for this. That is, they don't make it easy to generate the URLs that you would need to use to visit another resource. Now, this isn't a Node.js problem - this is much more widespread than that. I've seen frameworks for Java, Scala, Groovy, Ruby and Node - to mention the ones I've looked at myself - that have this problem. From memory, I think there's only two frameworks I've seen that actually do make URL generation easy. I was reasonably certain that JAX-RS for Java allows you to do this, but I can't find any documentation to say how you would do this. And the Escort router for node.js allows you to do this. In fact, Escort does it in a rather nice manner in that when you register routes you can optionally give the route a name, and then later on you can look up the route by name and generate a URL from it.

What Escort doesn't (currently) do is to generate full URLs. It generates the path part of the URL, since that's all it actually knows about. This has a problem if you want to spread your routing over multiple hostnames - which is unlikely - or if your routing is not at the base of your host - which is more likely. For example, if your entire REST application was mounted under /cmnd, Escort would need to know this to be able to write the URLs correctly. However, in theory that mounting is a deployment time concern and not something the code should ever need to know about.

All in all, it's a tricky problem that has yet to be solved well. But at least there are partial solutions out there that can be used in the interim.