Accessing External REST Services

You can access remote REST services by using the openidm/external/rest endpoint, or by specifying the external/rest resource in your scripts. Note that this service is not intended as a full connector to synchronize or reconcile identity data, but as a way to make dynamic HTTP calls as part of the OpenIDM logic. For more declarative and encapsulated interaction with remote REST services, and for synchronization or reconciliation operations, you should rather use the scripted REST connector.

An external REST call via a script might look something like the following:

openidm.action("external/rest", "call", params);

The "call" parameter specifies the action name to be used for this invocation, and is the standard method signature for the openidm.action method in OpenIDM 4.5.

An external REST call over REST might look something like the following:

$ curl \
 --cacert self-signed.crt \
 --header "Content-Type: application/json" \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request POST \
 --data '{
  "url": "http://www.december.com/html/demo/hello.html",
  "method": "GET",
  "detectResultFormat": false,
  "headers": { "custom-header": "custom-header-value" }
  }' \
 "https://localhost:8443/openidm/external/rest?_action=call"
{
  "body": "<!DOCTYPE html PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n
           <html>\r\n
           <head>\r\n
           <title>\r\n   Hello World Demonstration Document\r\n  </title>\r\n
           </head>\r\n
           <body>\r\n
           <h1>\r\n   Hello, World!\r\n  </h1>
           ...
           </html>\r\n",
  "headers": {
    "Server": "Apache",
    "ETag": "\"299-4175ff09d1140\"",
    "Date": "Mon, 28 Jul 2014 08:21:25 GMT",
    "Content-Length": "665",
    "Last-Modified": "Thu, 29 Jun 2006 17:05:33 GMT",
    "Keep-Alive": "timeout=15, max=100",
    "Content-Type": "text/html",
    "Connection": "Keep-Alive",
    "Accept-Ranges": "bytes"
  }
}

Note that attributes in the POST body do not have underscore prefixes. This is different to the OpenIDM 2.1 implementation, in which underscores were required.

HTTP 2xx responses are represented as regular, successful responses to the invocation. All other responses, including redirections, are returned as exceptions, with the HTTP status code in the exception "code", and the response body in the exception "detail", within the "content" element.

Invocation Parameters

The following parameters are passed in the resource API parameters map. These parameters can override the static configuration (if present) on a per-invocation basis.

  • url. The target URL to invoke, in string format.

  • method. The HTTP action to invoke, in string format.

    Possible actions include "POST", "GET", "PUT", "DELETE", and "OPTIONS".

  • authenticate. The authentication type, and the details with which to authenticate.

    OpenIDM 6.2 supports the following authentication types:

    • basic authentication, with a username and password, for example:

      "authenticate" : {"type": "basic", "user" : "john", "password" : "Passw0rd"}
    • bearer authentication, which takes an OAuth token, instead of a username and password, for example:

      "authenticate" : {"type": "bearer", "token" : "ya29.iQDWKpn8AHy09p....."}

    If no authenticate parameter is specified, no authentication is used.

  • headers. The HTTP headers to set, in a map format from string (header-name) to string (header-value). For example, Accept-Language: en-US.

  • content-type / contentType. The media type of the data that is sent, for example Content-Type: application/json when used in a REST command, or contentType: JSON when used in a script.

  • body. The body/resource representation to send (for PUT and POST operations), in string format.

  • detectResultFormat. Specifies whether JSON or non-JSON results are expected. Boolean, defaults to true.

    For all responses other than 2xx, the result is returned as an exception, with the HTTP code in the exception "code". Any details are returned in the exception "detail" under the "content" element. For example:

    $ curl \
     --cacert self-signed.crt \
     --header "Content-Type: application/json" \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request POST \
     --data '{
         "url":"http://december.com/non_existing_page",
         "method":"GET",
         "content-type":"application/xml"
       }' \
     "https://localhost:8443/openidm/external/rest?_action=call"
    {
        "detail": {
            "content": "<html><head><title>December Communications, Inc. Missing Page</title> (...) </html>\n"
        },
        "message": "Error while processing GET request: Not Found",
        "reason": "Not Found",
        "code": 404
    }

    For more information about non-JSON results, see "Support for Non-JSON Responses".

Support for Non-JSON Responses

The external REST service supports any arbitrary payload (currently in stringified format). The "detectResultFormat" parameter specifies whether the server should attempt to detect the response format and, if the format is known, parse that format.

Currently, the only known response format is JSON. So, if the service that is requested returns results in JSON format, and "detectResultFormat" is set to true (the default), the response from the call to external/rest will be the identical JSON data that was returned from the remote system. This enables JSON clients to interact with the external REST service with minimal changes to account for in the response.

If the service returns results in JSON format and "detectResultFormat" is set to false, results are represented as a stringified entry.

If "detectResultFormat" is set to true and the mime type is not recognized (currently any type other than JSON) the result is the same as if "detectResultFormat" were set to false. Set "detectResultFormat" to false if the remote system returns non-JSON data, or if you require details in addition to the literal JSON response body (for example, if you need to access a specific response header, such as a cookie).

The representation as parsed JSON differs from the stringified format as follows:

  • The parsed JSON representation returns the message payload directly in the body, with no wrapper. Currently, for parsed JSON responses, additional metadata is not returned in the body. For example:

    $ curl \
     --cacert self-signed.crt \
     --header "Content-Type: application/json" \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request POST \
     --data '{
         "url": "http://localhost:8080/openidm/info/ping",
         "method": "GET",
         "detectResultFormat": true,
         "headers": { "X-OpenIDM-Username": "anonymous", "X-OpenIDM-Password": "anonymous" }
       }' \
     "https://localhost:8443/openidm/external/rest?_action=call"
    {
      "shortDesc": "OpenIDM ready",
      "state": "ACTIVE_READY"
    }
  • The stringified format includes a wrapper that represents other metadata, such as returned headers. For example:

    $ curl \
     --cacert self-signed.crt \
     --header "Content-Type: application/json" \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request POST \
     --data '{
         "url": "http://localhost:8080/openidm/info/ping",
         "method": "GET",
         "detectResultFormat": false,
         "headers": { "X-OpenIDM-Username": "anonymous", "X-OpenIDM-Password": "anonymous" }
       }' \
     "https://localhost:8443/openidm/external/rest?_action=call"
    {
      "body": "{\"state\":\"ACTIVE_READY\",\"shortDesc\":\"OpenIDM ready\"}",
      "headers": {
        "Cache-Control": "no-cache",
        "Server": "Jetty(8.y.z-SNAPSHOT)",
        "Content-Type": "application/json;charset=UTF-8",
        "Set-Cookie": "session-jwt=eyAiYWxn...-cQ.3QT4zT4ZZTj8LH8Oo_zx3w;Path=/",
        "Expires": "Thu, 01 Jan 1970 00:00:00 GMT",
        "Content-Length": "52",
        "Vary": "Accept-Encoding, User-Agent"
      }
    }

    A sample non-JSON response would be similar:

    $ curl \
     --cacert self-signed.crt \
     --header "Content-Type: application/json" \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request POST \
     --data '{
         "url":"http://december.com",
         "method":"GET",
         "content-type":"application/xml",
         "detectResultFormat":false
       }' \
     "https://localhost:8443/openidm/external/rest?_action=call"
    {
      "body": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"
              \"http://www.w3.org/TR/html4/loose.dtd\"> \n
              <html><head><title>December Communications, Inc.
              december.com</title>\n
              <meta http-equiv=\"Content-Type\" content=\"text/html;
              charset=iso-8859-1\">
              ..."
      "headers": {
      "Server": "Apache",
      "ETag": "\"4c3c-4f06c64da3980\"",
      "Date": "Mon, 28 Jul 2014 19:16:33 GMT",
      "Content-Length": "19516",
      "Last-Modified": "Mon, 20 Jan 2014 20:04:06 GMT",
      "Keep-Alive": "timeout=15, max=100",
      "Content-Type": "text/html",
      "Connection": "Keep-Alive",
      "Accept-Ranges": "bytes"
      }
    }