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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"title": "My Blog Post", | |
"author": { | |
"name": "Graham", | |
"id": "graham" | |
}, | |
........ | |
} |
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"title": "My Blog Post", | |
"author": { | |
"name": "Graham", | |
"link": "http://localhost:8080/authors/graham", | |
"id": "graham" | |
}, | |
........ | |
} |
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.
No comments:
Post a Comment