I was wondering what would be the best approach to make a Grails app offer a RESTful API (some CRUD actions mainly) that can be used by a web service, e.g. when you want to build a corresponding iOS app to your browser-based app or anything else.
I thought of building a separate part in my Grails application that takes calls from www.mywebapp.com/api/someAction
so that I can reuse the Service layer. How would I do the URL mapping then? Only having one big ApiController
does not sound very groovy.
Or is there any better approach I did not know of? This approach must support something like OAuth to authenticate the user who is calling the Web service.
Go to start.grails.org and use the Grails Application Forge to generate your Grails project. You can choose your project type (Application or Plugin), pick a version of Grails, and choose a Profile - then click "Generate Project" to download a ZIP file. No Grails installation necessary!
Grails can definitely provide a REST api, but the level of difficulty in doing so varies depending on how mature (aka. how RESTful) you want the API to be.
Getting a basic level of RESTfullness, where you are manipulating json or xml representations of resources using the full span of HTTP verbs and leveraging the HTTP response codes, is pretty easy. There are 3 main pieces to getting that in place:
URL mapping
Here's an example of how I wrote my URL mappings on a recent project to allow for more RESTful URLs:
// RESTful list mapping name restEntityList: "/$controller"(parseRequest: true) { action = [GET: "list", POST: "save"] } // RESTful entity mapping name restEntity: "/$controller/$id"(parseRequest: true) { action = [GET: "show", PUT: "update", POST: "update", DELETE: "delete"] constraints { id matches: /\d+/ } }
Content negotiation
The 3 different ways that Grails can handle content negotiation make the framework very flexible, allowing you to support a much broader range of clients who may not be able to set things like the Accept HTTP header.
You can use the content negotiation to respond to different requests in different ways using the withFormat
block based on what the client has indicated they want. This powerful ability can also be used to version your API, much like how Github does.
Response status
HTTP already has a great response mechanism built into it that allows you to leverage innate abilities in the architecture, like cacheability and indemnipotent operations. While some web browsers don't handle certain response codes very gracefully, client applications using your API can use them to greatly simplify their internal code.
One of the best ways to make your application RESTful and keep it DRY at the same time is to leverage the controller scaffolding as much as possible, since CRUD is essentially the same for all domain objects. This article on making the default controller more RESTful, and this article on simplifying the default controller are both great resources for getting more power from the scaffolding.
Once you get to that point, you have a pretty functional REST API for your grails application. You can do all basic CRUD operations and the resources are fairly easy to work with.
The next levels of the ladder to a true RESTful hypermedia API, however, are much harder to attain. Fixing this is on the road map for Grails, but currently it's rather painful. These pieces are:
Thankfully, there is a plugin that makes defining custom marshallers very easy, which allows us to fairly easily cover those three remaining pieces of the REST puzzle.
Finally, there is the aspect of securing the whole thing. In general, Spring Security will hold you in good stead as far as securing user-access to your api. Since most API access is from an application, and isn't user-visible, basic or digest authentication is usually the simplest way to go. There is an OAuth plugin that builds on Spring Security. I have not personally used it so I can't vouch for it's stability, but it looks pretty good to me.
In general, Grails is flexible and powerful enough to do REST very, very well, but the work has not been done yet to make it do REST cleanly out-of-the-box.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With