Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to create a flexible API with grails
    primarykey
    data
    text
    <p>So a little background. I'm creating a website with quite a comprehensive api. The api should be able to handle changes, so therefore i have versioned the api, with api url equivalent to something like <code>/api/0.2/$apiKey/$controller/$action/$id</code>.</p> <p>I want to be able to reuse my controllers for the api as well as the standard html view. The solution was at first to use withFormat block in all my actions (through a private function shared between used in my action blocks).</p> <p>I don't like duplicate code, and therefore i want to centralize withFormat functionality. so instead of having a bunch of controllers and actions having their own withFormat block I would like it to be either a service (however, we don't have access to <code>render()</code> on services, do we?), or have a filter which can render the output according to grails content negotiation.</p> <p>My current solution has this filter defined:</p> <pre><code> after = { model -&gt; def controller = grailsApplication.controllerClasses.find { controller -&gt; controller.logicalPropertyName == controllerName } def action = applicationContext.getBean(controller.fullName).class.declaredFields.find{ field -&gt; field.name == actionName } if(model &amp;&amp; (isControllerApiRenderable(controller) || isActionApiRenderable(action))){ switch(request.format){ case 'json': render text:model as JSON, contentType: "application/json" return false case 'xml': render text:model as XML, contentType: "application/xml" return false default: render status: 406 return false } } return true } </code></pre> <p>As an example, all i have to do in the controller to render xml or json is:</p> <pre><code>@ApiRenderable def list = { def collectionOfSomething = SomeDomain.findAllBySomething('someCriteria') return [someCollection:collectionOfSomething] } </code></pre> <p>now if i access the the url that triggers this action list, (/api/0.2/apikey/controller/list.json or /api/0.2/apikey/controller/list?format=json or with headers: content-type: application/json) then the response would be encoded as follows:</p> <pre><code>{ someCollection: [ { someData: 'someData' }, { someData: 'someData2' } ] } </code></pre> <p>This is all very good if I always want to return a hashmap (which currently is a requirement from the controllers), but in this example all I wanted to return was the actual list! not a list wrapped within a hashmap....</p> <p>Does anyone have any pointers on how to create a good api functionality that is robust as well as flexible and that follows the DRY principle, that can handle versioning (<code>/api/0.1/</code>, <code>/api/0.2/</code>), and that can handle different marshalling approaches depending on the context in which it is returned? Any tips is appreciated!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload