Grails REST API config
- access control allow origin
- hidden OPTIONS method for non-https
- url mappings and naming convensions
Access control allow origin
Filter: enable Angular dev on a different port
if (Environment.developmentMode) {
header("Access-Control-Allow-Origin", "http://localhost:4200")
header("Access-Control-Allow-Credentials", "true")
header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS, PATCH")
header("Access-Control-Max-Age", "86400")
response.addHeader("Access-Control-Allow-Headers", "Authorization, Accept, Content-Type")
// In dev, always allow preflight OPTIONS cross origin request
if (ControllerPermission.isOptionMethodInDev(Environment.developmentMode, request.method)) {
render status: 200
return false // skip other filters (no more security check)
}
else {
return true // continue to run other filters
}
}
Each controller: have to provide an options action, so that Grails can make the browser happy
def options() {
render status: 200 // action to allow dev cross origin preflight OPTIONS request
}
Automatic OPTIONS method on the request
Cross domain non-https API requests would send an OPTIONS preflight request without Authorization header.
It returns 302 status and causes the subsequent e.g. GET request to be redirected.

To avoid this problem, we can:
- either: bypass security verification for OPTIONS requests in development mode
- or: skip the preflight request (use text/plain): http://stackoverflow.com/questions/22968406/how-to-skip-the-options-preflight-request-in-angularjs
For more information, refer to:
- http://stackoverflow.com/questions/29954037/how-to-disable-options-request
- https://www.w3.org/TR/cors/\#cross-origin-request-with-preflight-0
Url mappings and naming convensions
REST web service endpoints should have plural nouns as their names. The below specifies the convensions for the action names matching related http methods.
- endpoint without id + GET
- endpoint with id + method
- specific endpoint
"/api/$controller" {
action = [
GET : "index", // the index action, which is optional in Grails, returns all the items
OPTIONS: "options" // allow options for preflight request in dev
]
}
/*
* Rest web services - for all the controllers in the api package ending with a plural word
* */
"/api/$controller/$id" {
action = [
GET : "get", // show - get one item by id
PUT : "put", // update - by submitting full content
DELETE : "delete", // delete - delete one item by id
POST : "post", // create - by submitting full content
PATCH : "patch", // update - by submitting partial content - preferred not to use this for code simplicity
OPTIONS: "options" // allow options for preflight request in dev, bypassed by AngularDevFilters
]
}
/*
* Specific REST requests
* */
"/api/$controller/$action" {
constraints {}
}
Note:
- Most of the time, listing all the items require supplying a foreign key id (e.g. get all the charts for category 32)