Implement a REST API in a Grails app

浪子不回头ぞ 提交于 2019-11-29 18:57:43

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.

Basic REST

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:

  1. 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+/
        }
    }
    
  2. 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.

  3. 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.

DRY REST

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.

Advanced REST

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:

  1. Hypermedia resources
  2. Content types
  3. Versioning

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.

the grails documentation has a good walk though on setting up a RESTfull api

http://grails.org/doc/latest/guide/webServices.html#13.1

You can map it anyway, use any url structure. Grails UrlMapping is pretty flexible, it's only default behavior to map to /$controller/$action, but you can use your own mapping, you can event map each url manually, etc.

See UrlMapping docs - http://grails.org/doc/latest/guide/theWebLayer.html#urlmappings

  • url mapping:

    "/api/element/$version/$master" { controller = "element" action = [GET:"show"] }

This will map the http get to the show method of the controller element.

  • i.e. the show method:

DRY: The api is probably the same logic as the application. The difference is content negociation.

...

def show = {
    def elements = elementService.findByMasterVersion(params.master, params.version)
    withFormat {
        xml {
            render(status:200,text:elements as XML, contentType:"text/xml",encoding:"UTF-8")
        }
        json { ... }
        html { ... }
    }
}
  • Oauth is pretty damn complicated to implement and seems overkill for a lot of situation.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!