Create Custom Endpoints to Launch Scripts
Custom endpoints let you run arbitrary scripts through the REST URI.
Custom endpoints are configured in files named conf/endpoint-name.json
, where name generally describes the purpose of the endpoint. The endpoint configuration file includes an inline script or a reference to a script file, in either JavaScript or Groovy. The referenced script provides the endpoint functionality.
A sample custom endpoint configuration is provided in the openidm/samples/example-configurations/custom-endpoint
directory. The sample includes three files:
- conf/endpoint-echo.json
Provides the configuration for the endpoint.
- script/echo.js
Provides the endpoint functionality in JavaScript.
- script/echo.groovy
Provides the endpoint functionality in Groovy.
Note
This sample endpoint is described in detail in Create a Custom Endpoint.
Custom Endpoint Configuration File
An endpoint configuration file includes the following elements:
{ "context" : "endpoint/linkedView/*", "type" : "text/javascript", "source" : "require('linkedView').fetch(request.resourcePath);" }
context
string, optional
The context path under which the custom endpoint is registered, in other words, the route to the endpoint. An endpoint with the context
endpoint/test
is addressable over REST at the URLhttp://localhost:8080/openidm/endpoint/test
or by using a script such asopenidm.read("endpoint/test")
.Endpoint contexts support wild cards, as shown in the preceding example. The
endpoint/linkedview/*
route matches the following patterns:endpoint/linkedView/managed/user/bjensen endpoint/linkedView/system/ldap/account/bjensen endpoint/linkedView/ endpoint/linkedView
The
context
parameter is not mandatory in the endpoint configuration file. If you do not include acontext
, the route to the endpoint is identified by the name of the file. For example, in the sample endpoint configuration provided inopenidm/samples/example-configurations/custom-endpoint/conf/endpoint-echo.json
, the route to the endpoint isendpoint/echo
.Note
This
context
path is not the same as the context chain of the request. For information about the request context chain, see Request Context Chain.type
string, required
The type of script to be executed, either
text/javascript
orgroovy
.file
orsource
The path to the script file, or the script itself, inline.
For example:
"file" : "workflow/gettasksview.js"
or
"source" : "require('linkedView').fetch(request.resourcePath);"
Note
You must set authorization for any custom endpoints that you add, for example, by restricting the methods to the appropriate roles. For more information, see"Authorization and Roles".
Custom Endpoint Scripts
The custom endpoint script files in the samples/example-configurations/custom-endpoint/script
directory demonstrate all the HTTP operations that can be called by a script. Each HTTP operation is associated with a method
- create
, read
, update
, delete
, patch
, action
, or query
. Requests sent to the custom endpoint return a list of the variables available to each method.
All scripts are invoked with a global request
variable in their scope. This request structure carries all the information about the request.
Warning
Read requests on custom endpoints must not modify the state of the resource, either on the client or the server, as this can make them susceptible to CSRF exploits.
The standard READ endpoints are safe from Cross Site Request Forgery (CSRF) exploits because they are inherently read-only. That is consistent with the Guidelines for Implementation of REST, from the US National Security Agency, as "... CSRF protections need only be applied to endpoints that will modify information in some way."
Custom endpoint scripts must return a JSON object. The structure of the return object depends on the method
in the request.
The following example shows the create
method in the echo.js
file:
if (request.method === "create") { return { method: "create", resourceName: request.resourcePath, newResourceId: request.newResourceId, parameters: request.additionalParameters, content: request.content, context: context.current } }
The following example shows the query
method in the echo.groovy
file:
else if (request instanceof QueryRequest) { // query results must be returned as a list of maps return [ [ method: "query", resourceName: request.resourcePath, pagedResultsCookie: request.pagedResultsCookie, pagedResultsOffset: request.pagedResultsOffset, pageSize: request.pageSize, queryId: request.queryId, queryFilter: request.queryFilter.toString(), parameters: request.additionalParameters, context: context.toJsonValue().getObject() ] ] }
Depending on the method, the variables available to the script can include the following:
resourceName
The name of the resource, without the
endpoint/
prefix, such asecho
.newResourceId
The identifier of the new object, available as the results of a
create
request.revision
The revision of the object.
parameters
Any additional parameters provided in the request. The sample code returns request parameters from an HTTP GET with
?param=x
, as"parameters":{"param":"x"}
.content
Content based on the latest revision of the object, using
getObject
.context
The context of the request, including headers and security. For more information, see Request Context Chain.
- Paging parameters
The
pagedResultsCookie
,pagedResultsOffset
, andpageSize
parameters are specific toquery
methods. For more information see "Page Query Results".- Query parameters
The
queryId
andqueryFilter
parameters are specific toquery
methods. For more information see "Construct Queries".
Script Exceptions
Some custom endpoint scripts require exception-handling logic. To return meaningful messages in REST responses and in logs, you must comply with the language-specific method of throwing errors.
A script written in JavaScript should comply with the following exception format:
throw { "code": 400, // any valid HTTP error code "message": "custom error message", "detail" : { "var": parameter1, "complexDetailObject" : [ "detail1", "detail2" ] } }
Any exceptions will include the specified HTTP error code, the corresponding HTTP error message, such as Bad Request
, a custom error message that can help you diagnose the error, and any additional detail that you think might be helpful.
A script written in Groovy should comply with the following exception format:
import org.forgerock.json.resource.ResourceException import org.forgerock.json.JsonValue throw new ResourceException(404, "Your error message").setDetail(new JsonValue([ "var": "parameter1", "complexDetailObject" : [ "detail1", "detail2" ] ]))