What is an efficient way to create/manage RESTful API with grails?
api, grails, rest, restful-authentication
Solution
Before even looking below for my opinion/answers I would suggest to visit this SO Question for the basic understanding of RESTful WS in Grails.
Opinions:
"The save action should accept parameters as JSON and provide a successful message if the records save" - Save is mapped to POST RESTful. Instead of binding a JSON body to `params` it is bound to the `request`. In order to access the JSON object you just need to use `request.JSON` in the action method.
`request.JSON instanceof JSONObject`
- "The list action should provide the list as JSON" - `list()` action is mapped to a GET Request and you can render the map as JSON in the `list()` as below
//Controller list()
import grails.converter.JSON
def list () {
[colorList: Color.list, colorTotal: Color.count()] as JSON
}
Answers to Questions:-
- Should I make a separate URL mapping for api? Abiding by the basics of REST, the client should only access the resource (`Color` in this case) and should not bother about the underlying `controller` or `action`. The server side logic should be abstracted from the client. URL Mapping is what the client would use to as form of request. I would have something like this in my url mapping for `Color` Resource.
`/color/$id?(resource: "color")`
or
/color/$id?(controller: 'color'){
action = [GET: "list", POST: "save"]
}
Should I be making a separate controller for my API's? - Depends on the way the App is designed. You also can have the above controller as the API. For example, currently I am working on a grails app which used `AngularJS` in the front End which connects to the Grails APP RESTFully. In order to achieve I had a `RestClientController` which works as an API to Angular. The rationale behind having a REST api in the same app is that in future we can expose the underlying service to external clients other than the `Angular` client present in the app itself.
I am using spring security plugin for authentication. But at some point I might want to authenticate the restful api as well. What are some solutions for that? - You can use Spring Security here as well. In my case I am using the plugin and I secure the `controller` by using the plugin's annotated component `@Secured`. I have custom `OAuth` enabled as well for authorization which interacts to the company wide LDAP and AD Groups.
If I use the same controller, how can I modify these simple actions to do what I need. - I think you would have got the answer to this question by now (after going through the SO question I mentioned above). Here is my opinion, `controller` `actions` can route to appropriate `service` classes which does the business implementations based on the request parameters.
For example,
//Action
def show(){
if(params.id){
colorService.getColor()
} else {
colorService.searchColor()
}
}
In the above example, the url mapping would be `/color/123` or `/color`. In the former case, it will get the `color` and in the later it will search the colors
Problem
I've built my first grails application. My URL mappings are what the default application provides: ``` static mappings = { "/$controller/$action?/$id?"{ constraints { // apply constraints here } } "/"(view:"/index") "500"(view:'/error') } ``` Senario I have a controller called `ColorController` with actions `save` and `list`. It simply does something like this: ``` def save () { def colorInstance = new Color(params) colorInstance.save(flush: true) } def list () { [colorList: Color.list, colorTotal: Color.count()] } ``` I would like to build a simple API for these actions. - The save action should accept parameters as JSON and provide a successful message if the records save. - The list action should provide the list as JSON Questions - Should I make a separate URL mapping for api? (e.g. `http://<domain>/<app>/rest/controller/action`) - Should I be making a separate controller for my API's - I am using spring security plugin for authentication. But at some point I might want to authenticate the restful api as well. What are some solutions for that? - If I use the same controller, how can I modify these simple actions to do what I need.