Event Handlers
Event Handlers
calac41
You can do more processing and customization using event handlers. Request and response event handlers are JavaScript entry points to perform user-defined actions.
API Server calls the following types of event handlers for every request:
- Requests.API Server invokes these event handlersafterit receives the request butbeforeit processes request/row mapping and reactive logic.
- Responses.API Server invokes these event handlersbeforeit sends the (successful) final result to the client.
- HTTP Options.API Server recognizes Cross-Origin Resource Sharing (CORS) OPTIONS requests and invokes these event handler only for these requests.
In this article:
3
Create an Event Handler
There is no limit to the number of event handlers you can create.
- With your API open, in the Manage section, clickRequest Events.
- If your API does not have existing request and response event handlers, the Welcome to Request and Response Events page appears. If your API has existing request and response event handlers, they are listed on the Events page.
- Complete one of the following:
- If you have not defined any request and response event handlers, on the Welcome to Request and Response Events page, clickCreate Event.
- If you have at least one request and response event handler defined, clickAdd.
- Complete the following fields on the page, and then save your changes:Event typeThe type of event handler.Options:Request, Response, HTTP OptionsDefault:RequestYou can create only one HTTP Options event handler per API.Event Handler nameThe name for your event handler.CA Live API Creatorinvokes request and response event handlers in alphabetical order based on their name.You can haveCA Live API Creatorinvoke the event handler in a specific order by appending the event handler name with a number sequence.CodeThe operations for this event handler. For example:if (“SalesResports” == req.resourceName) { //log.debug(‘***SalesReports Req Event - json: ' + json); var data = JSON.parse(json); // json from the request var theOrder = data[0]; var keptItemNum = 0; var keptItems = []; log.debug(“theOrder: " + JSON.stringify(theOrder)); for ( var i = 0; i < theOrder.Order_DetailsList.length; i ++) { var eachItem = theOrder.Order_DetailsList(i); delete eachItem[“@metadata”]; if (eachItem.SupplierName == “Pavlova, Ltd.”) { delete eachItem.OrderID; delete eachItem.ProductID;...ActiveSelect to indicate that this event handler is active.
The event handler is created.
How API Server Invokes Event Handlers
The following section describes how API Server invokes each event handler.
Request Event Handlers
API Server invokes request event handlers using the following process:
- API Server performs initial authentication.
- API Server invokes the request event handler for every transaction, with the following variables pre-defined:Variable NameDescriptionjsonThe raw JSON string that the client sends, if any. Set only for POST and PUT requests. You can modify this string.reqThe
object. For more information about this object, see The req Object.reqlogThe logger for the current request.headersThe headers sent as part of the HTTP request. Excludes authorization headers. - API Server establishes a connection to the database.
- API Server parses the JSON payload.
For more information about how API Server processes update requests, including how rules integrate with request event handlers, see Logic Execution.
Request Event Handler Examples
In the following example, API Server rejects all requests on
SecretData
if the request does not use HTTPS:// Reject all requests on SecretData if they do not use HTTPSif ("SecretData" == req.resourceName && !req.clientUsesHttps) { log.error('SecretData was accessed over HTTP by ' + req.clientAddress); throw "Use HTTPS to access this resource";}
In the following example, API Server deletes all data from requests except the data included in the JSON payload:
// Remove extraneous data that the client sends but that is not needed.if ( ! json) { // Only requests with a JSON payload are needed. return;}var data = JSON.parse(json);if (Array.isArray(data)) { for (var i = 0; i < data.length; i++) { delete data[i].uselessData; }}else { delete data.uselessData;}// Important: Serialize the data back to a string if you want to change itjson = JSON.stringify(data);
Response Event Handlers
API Server invokes response event handlers with the following variables pre-defined:
Variable name | Description |
| The complete response object, which is sent back to the client after the response event handlers (if any) have been executed. You can (carefully) change or replace this object. The object is different from request event handlers. This variable is not a string, but rather an object or an array of objects. For a GET, this variable is a single object or an array of objects depending on the details of the request. For PUT/POST/DELETE, this variable is a single object with , , elements. This variable can also be an error result. The method must be able to stringify the JSON object. |
| The object. For more information about this object, see The req Object. |
| The object. |
| The logger for the request. |
| The SysUtility object.For more information about this object, see The SysUtility Object. |
Response Event Handler Examples
The Sample database illustrates preparing a partner-specific response by materializing a resource and returning it as the response message. Resource object/attribute aliases are defined to match partner expectations:
// Remove all @metadata sections from the response for a specific table/resource// Note: This would make it difficult for the client to update the data, but this is only an example.// This only deals with top-level resources. To remove all// @metadata sections from a complex resource, use recursion.// An attribute 'TheVerb' is added to each array object or the single object// with the name of request verb - GET, PUT, POST, PATCH, DELETE// get the name used for metadata (configurable by project).// You CAN convert from the Java string value to a JavaScript string object herevar metadataName = "@metadata"; if (Array.isArray(json)) { // If the response is an array of objects for (var i = 0; i < json.length; i++) { delete json[i][metadataName]; json[i].txsummary && delete json[i].txsummary[0][metadataName]; // You MUST convert to native JavaScript string json[i].TheVerb = req.verb; } } else { // The response is a single object delete json[metadataName]; json.txsummary && delete json.txsummary[0][metadataName]; json.TheVerb = req.verb; }
For more information:
- About resource object/attribute aliases matching partner expectations, see Logic Patterns.
- About the Sample database, see Sample Database.
The following code snippet adds the top 30 (by
)amount_total
where the employee is the sales rep by augmenting each employee in a GET of multiple employees:purchaseorders
// for a GET to an employee, add any PURCHASEORDERS where the employee is a sales repif ("GET" == req.verb && "demo:employee" == req.resourceName) { var ordersAsSalesRep = []; for (var i = 0; i < json.length; i++ ) { // want purchase orders for this employee as sales rep // top thirty purchase orders by amount_total var detail = { filter: '"salesrep_id" = ' + json[i].employee_id , order: '"amount_total" desc', pagesize: 10, offset: 0 }; if(json[i].employee_id) { ordersAsSalesRep = SysUtility.getResource("PurchaseOrders", detail); json[i].ordersAsSalesRep = ordersAsSalesRep; } } }
The following code snippet includes the results of a resource GET by amending the transaction summary:
// for a PUT (perhaps to update the name) of one or more employees// add the picture into the resultif ("PUT" == req.verb && "demo:employee" == req.resourceName) { var txsummary = json.txsummary; for (var i = 0, len = txsummary.length; i < len; i += 1) { var meta = txsummary[i]["@metadata"]; if ("UPDATE" == meta.verb && "demo:employee" == meta.resource) { var detail = { filter: '"employee_id" = ' + txsummary[i].employee_id }; var picInfo = SysUtility.getResource("the_employee_picture", detail); if (picInfo && picInfo.length > 0) { txsummary[i].the_picture = picInfo[0].picture; } } } }
You can combine these examples and delete the usual transaction summary, redirecting it to be the
getResource()
method result. For more information about transaction summaries, see Transaction Summary.
HTTP Options Event Handlers
Protect your data from unauthorized access by creating an HTTP Options event handler for your API. You can get complete control over the response to CORS OPTIONS preflight requests with HTTP Options event handler.
For more information:
- About CORS OPTIONS preflight requests, see the Mozilla website.
- About security inCA Live API Creator, see Security.
HTTP Options Event Handler Example
The following code snippet shows an example of an HTTP Options event handler:
return { "Access-Control-Allow-Methods" : "GET,PUT,POST,DELETE", "Access-Control-Allow-Origin" : "https://internal.acme.com,https://safe.acme.com", "Access-Control-Allow-Headers" : "authorization,content-type,accept,x-requested-with,X-CALiveAPICreator-ResponseFormat", "Access-Control-Max-Age" : 2400 , "HTTPStatusCode" : 200};
This code instructs the client web browser that this API expects calls only from the specified URLs. API Creator invokes the handler only if the request includes an
Access-Control-Request-Method
header or an Access-Control-Request-Headers
header.Advanced Usage
To view an advanced example of using event handlers, see Integrate Systems and Data.
Modify the JSON Response
You have full control over the result. The following is an example:
- Define a newMyResourceJavaScript resource, for example:return { Happy: ['New', 'Year']};For more information about how to explicitly define a JavaScript resource in API Creator, see Define JavaScript Resource Types.
- In the REST Lab, view the result by performing a GET request, which is a different formatting of the previous JSON. Complete the following steps:
- Ensure that you are functioning by defining a simple response event handler that includes the following code:// MUST be an object or an array, if not, it is coerced into one (and probably NOT what you want)if ('GET' == req.verb && 'MyResource' == req.resourceName) { json = ["I got what I expected"];}else { // this is returned on ALL other requests, make sure you delete this !!! json = ["Not what I wanted"];}
- Change to a more specific handler without the else condition:// Note double equals, as you are comparing JavaScript strings with java.lang.String objectsif ('GET' == req.verb && 'MyResource' == req.resourceName) { json = SysUtility.getResource('demo:customer');}
The handler takes a value from the request and modifies the JSON response from the
resource.demo:customer
Access Request Headers
Request handlers have full access to the
headers
in the incoming request. Your handler has access to the headers
object, for example://header names are usually lowercasevar contentType = headers["content-type"];
Modify the Response
Response handlers can modify the outgoing response in multiple ways. The
response
variable is an instance of the javax.ws.rs.core.Response.ResponseBuilder
Java class.For more information about the
Response.ResponseBuilder
Java class, see the Oracle documentation.In the response handler, you can modify the response by adding headers, adding cookies, and setting the response code, for example:
var NewCookie = Java.type("javax.ws.rs.core.NewCookie");var cookie = new NewCookie("MyCookie", "My cookie value");response.cookie(cookie);response.header("X-my-special-header", "My header value");response.status(299);