Hooks
This page gives specific examples and reference for implementing hooks in MWS. For more information and a description of hooks, see the hooks section in the user guide.Available Hooks
The following table lists the available hooks for each resource with their associated HTTP method and description.Name | HTTP Method | Description |
---|---|---|
beforeList | GET | Runs before an API call that lists resources. ex: GET /rest/jobs |
afterList | GET | Runs after an API call that lists resources. |
beforeShow | GET | Runs before an API call that returns a single resource. ex: GET /rest/jobs/job.1 |
afterShow | GET | Runs after an API call that returns a single resource. |
beforeSave | POST | Runs before an API call that saves a new resource. ex: POST /rest/jobs |
afterSave | POST | Runs after an API call that returns a single resource. |
beforeUpdate | PUT | Runs before an API call that returns a single resource. ex: PUT /rest/jobs/job.1 |
afterUpdate | PUT | Runs after an API call that returns a single resource. |
beforeDelete | DELETE | Runs before an API call that returns a single resource. ex: DELETE /rest/jobs/job.1 |
afterDelete | DELETE | Runs after an API call that returns a single resource. |
If a resource does not support a certain operation, any hooks for that operation will simply be ignored, such asbeforeSave
andafterSave
hooks for the Node resource, where saving is not supported.
Available Properties
The following table lists the properties, objects, and methods available in all hooks. Note that although it is possible to directly call therender*
methods in the after
hooks, it is not recommended. Please see the user guide for more information.Name | Type | Description |
---|---|---|
params | Map | Contains all URL parameters as well as the body of the request as parsed JSON. |
request | HttpServletRequest | Contains properties of the HTTP request. |
response | HttpServletResponse | Contains properties of the HTTP response which can be modified directly. |
session | HttpSession | Contains the session parameters which can be modified directly. |
flash | Map | Temporary storage that stores objects within the session for the next request only. |
controllerName | String | The name of the controller responding to the request. Only available in before hooks. |
actionName | String | The name of the action to be run on the controller. Only available in before hooks. |
apiVersion | String | The API version for the current request (i.e. 1 for 7.0 and 7.1, 2 for 7.2). |
The parsed JSON may be accessed inIn addition, several methods are available to the hooks. These are described in the following sections.before
hooks as a simple groovy Map withparams[controllerName]
.
Redirect
Theredirect
method may be used to redirect the request to another API call or an arbitrary URL.redirect(uri:'/rest/jobs') // uri is used for internal redirection within MWS redirect(url:'http://adaptivecomputing.com') // url is used for external redirection redirect(uri:'http://adaptivecomputing.com', params:[lang:'en']) // params may be used for URL parameters
The redirect
method will use the GET HTTP method for the resulting redirected request.
See the redirect
method's documentation for more information.Rendering Objects, Lists, or Messages
There are severalrender*
methods available to handle any case where objects or lists are desired to be rendered directly from the hook
without continuing to the API call. Three different methods may be used depending on the desired output object type:Render Object
// Object that should be rendered as JSON
def objectToRender = …
// HTTP response code (bad request)
def responseCode = 400// Render a simple object
renderObject(objectToRender)
// Render a simple object with a custom response code
renderObject(objectToRender, responseCode)
Render List
// List that should be rendered as JSON def listToRender = … // If the totalCount property differs from resultCount, use this value instead def totalCount = … // HTTP response code (bad request) def responseCode = 400// Render a simple list // Dynamically adds "resultCount" and "totalCount" properties based on the size of the input list renderList(listToRender) // Render a simple list with a custom "totalCount" renderList(listToRender, totalCount) // Render a simple list without changing the "totalCount" but with a custom response code renderList(listToRender, null, responseCode) // Render a simple list with a custom "totalCount" and response code renderList(listToRender, totalCount, responseCode)
Render Message(s)
// Messages def messageToRender = "Single message" def messagesListToRender = ["Message 1", "Message 2"] // HTTP response code (bad request) def responseCode = 400// Render messages as an object with a property of "messages" containing a list of the messages passed in renderMessages(messageToRender) renderMessages(messageToRender, responseCode) // Supports either a single String or list of Strings renderMessages(messagesListToRender) renderMessages(messagesListToRender, responseCode)
It is not recommended to call any of these methods from an after
hook.
Render
Less commonly used, therender
method is also available directly. This may be used to render text directly, change the content-type
of the output, and many other functions. See the render
method's documentation
for more information.It is not recommended to call this method from an after
hook.
Serialize Objects
TheserializeObject
and serializeList
methods may be used to convert a custom object or list respectively into a format usable
for returning in the after
hooks. Simply pass in the object or list and a serialized version will be returned from the method.def afterShow = {
def objectToRender = …
def serializedObject = serializeObject(objectToRender)
return serializedObject
}
def afterShow = {
def listToRender = [...]
def serializedList = serializeList(listToRender)
return serializedList
}
Error Handling
Error handling is only available inafter
hooks by using the following check:if (!isSuccess()) { // Handle error return … // False or modified object/list to render }
Usage Examples
Override an API Call
The following hook would serve to override an entire API call, the list call in this case, and return amessages
list containing
a single element of "Action is not supported" and a HTTP response code of 405
(Method Not Allowed):def beforeList = { renderMessages("Action is not supported", 405) return false }
vms.groovy
file:def beforeDelete = { renderMessages("Virtual Machine deletion is not allowed", 405) return false }
Add An Additional Property During Job Creation
To add an additional property to a job definition during creation, create abeforeSave
hook in the jobs.groovy
file as follows:def beforeSave = { // params[controllerName] is equivalent to params["job"] or params.job params[controllerName].user = "myuser" }
myuser
.Redirect Based on URL Parameter
To redirect an API call if a certain URL parameter exists, create abeforeSave
hook in the jobs.groovy
file as follows:def beforeSave = { if (params.external) { redirect(url:'http://example.com/create-job') return false; // Stop API call } }
PUT /rest/jobs?external=1
to redirect to GET http://example.com/create-job
.Remove a Property From Getting a Single Job
To remove a property from the output of getting a single job, create anafterShow
hook in the jobs.groovy
file as follows:def afterShow = { o -> o.discard("group") return o }
group
property of the job resource. Note again that these calls must use the
JSONArray and
JSONObject classes as mentioned in the user guide.Filter List Items
To filter the items in a list nodes request based on user provided query parameter in the URL, use the following in thenodes.groovy
file.
A sample request that would activate the filter is http://localhost/mws/rest/nodes?filter-power=On
.def afterList = { o -> // Do not filter if the user did not ask for it if (!params['filter-power']) return o // o = {resultCount: x, totalCount: x, results:[...]} // Using a built-in groovy method findAll to return all // list items that return true from the block def results = o.results.findAll { node -> // Includes the node only if the power equals the user input return params['filter-power'].equalsIgnoreCase(node.power) } // Sets the results on the return object and updates the counts o.element("results", results) o.element("resultCount", results.size()) return o }
nodes.groovy
file.def afterList = { o -> // o = {resultCount: x, totalCount: x, results:[...]} // Using a built-in groovy method findAll to return all // list items that return true from the block def results = o.results.findAll { node -> // Includes the node only if the variable "included" is set to "true" return node.variables?.included=="true" } // Sets the results on the return object and updates the counts o.element("results", results) o.element("resultCount", results.size()) return o }