appendix-rest.xml revision 786c8a76edf4275c0c85b200563c8f318641b088
<?xml version="1.0" encoding="UTF-8"?>
<!--
! CCPL HEADER START
!
! This work is licensed under the Creative Commons
! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
! To view a copy of this license, visit
! http://creativecommons.org/licenses/by-nc-nd/3.0/
! or send a letter to Creative Commons, 444 Castro Street,
! Suite 900, Mountain View, California, 94041, USA.
!
! You can also obtain a copy of the license at
! legal/CC-BY-NC-ND.txt.
! See the License for the specific language governing permissions
! and limitations under the License.
!
! If applicable, add the following below this CCPL HEADER, with the fields
! enclosed by brackets "[]" replaced with your own identifying information:
! Portions Copyright [yyyy] [name of copyright owner]
!
! CCPL HEADER END
!
! Copyright 2011-2014 ForgeRock AS
!
-->
<appendix xml:id='appendix-rest'
xmlns='http://docbook.org/ns/docbook'
version='5.0' xml:lang='en'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://docbook.org/ns/docbook
http://docbook.org/xml/5.0/xsd/docbook.xsd'
xmlns:xlink='http://www.w3.org/1999/xlink'>
<title>REST API Reference</title>
<indexterm>
<primary>Objects</primary>
<secondary>Managed objects</secondary>
</indexterm>
<indexterm>
<primary>REST API</primary>
</indexterm>
<para>
Representational State Transfer (REST) is a software architecture style for
exposing resources, using the technologies and protocols of the World Wide
Web. REST describes how distributed data objects, or resources, can be
defined and addressed. OpenIDM provides a RESTful API for accessing managed
objects, system objects, workflows, and some elements of the system
configuration.
</para>
<para>
The ForgeRock implementation of REST, known as commons REST (CREST), defines
an API intended for common use across all ForgeRock products. CREST is a
framework used to access various web resources, and for writing to RESTful
resource providers (servers).
</para>
<para>
CREST is intended to support the following types of operations, described in
detail in <xref linkend="rest-supported-operations" />:
<literal>Create</literal>, <literal>Read</literal>,
<literal>Update</literal>, <literal>Delete</literal>,
<literal>Action</literal>, and <literal>Query</literal>.
</para>
<para>
ForgeRock defines a JSON Resource core library, as a common framework to
implement RESTful APIs. That core library includes two components:
</para>
<variablelist>
<varlistentry>
<term><literal>json-resource</literal></term>
<listitem>
<para>
A Maven module that provides core interfaces such as <literal>
Connections</literal>, <literal>Requests</literal>, and
<literal>Request Handlers</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>json-resource-servlet</literal></term>
<listitem>
<para>
Provides J2EE servlet integration. Defines a common HTTP-based REST API
for interacting with JSON resources.
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
You can examine the libraries associated with ForgeRock REST at
http://commons.forgerock.org/forgerock-rest.
</para>
</note>
<section xml:id="rest-uri-scheme">
<title>URI Scheme</title>
<para>The URI scheme for accessing a managed object follows this
convention, assuming the OpenIDM web application was deployed at
<literal>/openidm</literal>.</para>
<literallayout class="monospaced">/openidm/managed/<replaceable
>type</replaceable>/<replaceable>id</replaceable></literallayout>
<para>
Similar schemes exist for URIs associated with all but system objects.
For more information, see the reference on the <link
xlink:href="integrators-guide#access-js"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>
access.js</citetitle></link> file.
</para>
<para>
The URI scheme for accessing a system object follows this convention:
</para>
<literallayout class="monospaced">/openidm/system/<replaceable
>resource-name</replaceable>/<replaceable>type</replaceable>/<replaceable
>id</replaceable></literallayout>
<para>
An example of a system object in an LDAP repository might be:
</para>
<literallayout class="monospaced">
/openidm/system/ldap/account/07b46858-56eb-457c-b935-cfe6ddf769c7
</literallayout>
<para>
Note that for LDAP resources, you should not map the LDAP
<literal>dn</literal> to the OpenIDM <literal>uidAttribute</literal>
(<literal>_id</literal>). The attribute that is used for the
<literal>_id</literal> should be immutable. You should therefore map the LDAP
<literal>entryUUID</literal> operational attribute to the OpenIDM
<literal>_id</literal>, as shown in the following excerpt of the provisioner
configuration file:
</para>
<programlisting>...
"uidAttribute" : "entryUUID",
... </programlisting>
</section>
<section xml:id="rest-object-identifier">
<title>Object Identifiers</title>
<indexterm>
<primary>Objects</primary>
<secondary>Managed objects</secondary>
<tertiary>Identifiers</tertiary>
</indexterm>
<para>
Every managed and system object has an identifier (expressed as
<replaceable>id</replaceable> in the URI scheme) that is used to address the
object through the REST API. The REST API allows for client-generated and
server-generated identifiers, through PUT and POST methods. The default
server-generated identifier type is a UUID. If you create an object by using
<literal>POST</literal>, a server-assigned ID is generated in the form of a
UUID. If you create an object by using PUT, the client assigns the ID in
whatever format you specify.
</para>
<para>
Most of the examples in this guide use client-assigned IDs, as it makes the
examples easier to read.
</para>
<para>
For more information on whether to use PUT or POST to create managed objects,
see <xref linkend="put-post-managed-objects" />.
</para>
</section>
<section xml:id="rest-content-negotiation">
<title>Content Negotiation</title>
<para>The REST API fully supports negotiation of content representation
through the <literal>Accept</literal> HTTP header. Currently, the supported
content type is JSON. In most cases, you should include the following
header:</para>
<literallayout class="monospaced">Accept: application/json</literallayout>
<para>
In a REST call (using the <command>curl</command> command, for example),
you would include the following option to specify the noted header:</para>
<literallayout class="monospaced">--header "Content-Type: application/json"</literallayout>
<para>You can also specify the default UTF-8 character set as follows:</para>
<literallayout class="monospaced">--header "Content-Type: application/json;charset=utf-8"</literallayout>
<para>
The <literal>application/json</literal> content type is not needed when a
REST call is made with the GET and DELETE methods.
</para>
</section>
<section xml:id="rest-supported-operations">
<title>Supported Operations</title>
<para>
CREST supports several types of operations for communication with web
servers.
</para>
<para>
The following request parameters can be used in conjunction with the
supported operations.
</para>
<variablelist>
<varlistentry>
<term><literal>_fields</literal></term>
<listitem>
<para>
The <literal>_fields</literal> parameter can be used to return multiple
common attributes.
</para>
<para>
For example, you can use <literal>GET</literal> to read specific
attributes for a user as follows:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET
"https://localhost:8443/openidm/managed/user/james?_fields=userName,mail"</userinput>
<computeroutput>{
"mail": "james@example.com",
"userName": "james"
}</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>_prettyPrint=[true,false]</literal></term>
<listitem>
<para>
If <literal>_prettyPrint=true</literal>, the <literal>HttpServlet</literal>
formats the response, in a fashion similar to the JSON parser known
as <link xlink:href="http://stedolan.github.io/jq/">jq</link>.
</para>
<para>
For example, adding <literal>_prettyPrint=true</literal> to the end of
a <literal>query-all-ids</literal> request formats the output in the
following manner:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids&amp;_prettyPrint=true"</userinput>
<computeroutput>{
"result" : [ {
"_id" : "bjensen",
"_rev" : "0"
}, {
"_id" : "scarter",
"_rev" : "0"
}, {
"_id" : "jberg",
"_rev" : "0"
} ],
"resultCount" : 3,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</computeroutput>
</screen>
<para>
Note that most command-line examples in this guide do not show this
parameter, although the output in the examples is formatted for
readability.
</para>
</listitem>
</varlistentry>
</variablelist>
<section xml:id="rest-supported-create">
<title>Creating an Object</title>
<para>
Objects can be created with two different HTTP operations:
<literal>POST</literal> and <literal>PUT</literal>.
</para>
<para>
To create an object with a server-assigned ID, use the
<literal>POST</literal> operation with the <literal>create</literal> action.
For example:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{
"userName":"mike",
"sn":"Smith",
"givenName":"Mike",
"mail": "mike@example.com",
"telephoneNumber": "082082082",
"password":"Passw0rd"
}'
"https://localhost:8443/openidm/managed/user?_action=create"</userinput>
<computeroutput>{
"userName": "mike",
...
"_rev": "1",
"_id": "a5bed4d7-99d4-41c4-8d64-49493b48a920",
...
}</computeroutput></screen>
<para>
To create an object with a client-assigned ID, use the
<literal>PUT</literal> operation, with either of the following headers:
</para>
<simplelist type="vert" columns="1">
<member><literal>If-None-Match: *</literal></member>
<member><literal>If-None-Match: "*"</literal></member>
</simplelist>
<para>
Specify the ID as part of the URL, for example:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-None-Match: *"
--request PUT \
--data '{
"userName":"james",
"sn":"Berg",
"givenName":"James",
"mail": "james@example.com",
"telephoneNumber": "082082082",
"password":"Passw0rd"
}' \
"https://localhost:8443/openidm/managed/user/james"</userinput>
<computeroutput>{
"userName": "james",
...
"_rev": "1",
...
"_id": "james",
...
}</computeroutput>
</screen>
</section>
<section xml:id="rest-supported-read">
<title>Reading an Object</title>
<para>
To read the contents of an object, use the <literal>GET</literal>
operation, specifying the object ID. For example:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/system/ldap/account/fc252fd9-b982-3ed6-b42a-c76d2546312c"</userinput>
<computeroutput>{
"givenName": "Barbara",
"telephoneNumber": "1-360-229-7105",
"dn": "uid=bjensen,ou=People,dc=example,dc=com",
"description": "Created for OpenIDM",
"mail": "bjensen@example.com",
"ldapGroups": [
"cn=openidm2,ou=Groups,dc=example,dc=com"
],
"cn": "Barbara Jensen",
"uid": "bjensen",
"sn": "Jensen",
"_id": "fc252fd9-b982-3ed6-b42a-c76d2546312c"
} </computeroutput></screen>
</section>
<section xml:id="rest-supported-update">
<title>Updating an Object</title>
<para>
An update replaces some or all of the contents of an existing object. Any
object can be updated over REST with a PUT request. <emphasis>Managed
objects</emphasis> can also be updated with a POST request, using the
<literal>patch</literal> action, or with a PATCH request.
</para>
<para>
To update an object with a <literal>PUT</literal> request, use the
<literal>If-Match</literal> header, for example:
</para>
<screen>$ <userinput> curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-Match : *" \
--request PUT \
--data '{"description":"The new description for Babs Jensen"}'
"https://localhost:8443/openidm/system/ldap/account/fc252fd9-b982-3ed6-b42a-c76d2546312c"</userinput>
<computeroutput>{
"givenName": "Barbara",
"telephoneNumber": "1-360-229-7105",
"dn": "uid=bjensen,ou=People,dc=example,dc=com",
"description": "The new description for Babs Jensen",
"mail": "bjensen@example.com",
"ldapGroups": [
"cn=openidm2,ou=Groups,dc=example,dc=com"
],
"cn": "Barbara Jensen",
"uid": "bjensen",
"sn": "Jensen",
"_id": "fc252fd9-b982-3ed6-b42a-c76d2546312c"
} </computeroutput></screen>
<para>
To update a managed object with a POST request, use the
<literal>patch</literal> action and specify the updated fields as an array in
the <literal>data</literal> option. For example:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '[
{
"operation":"replace",
"field":"/description",
"value":"The new description for James"
}
]'
"https://localhost:8443/openidm/managed/user/james?_action=patch"</userinput>
<computeroutput>{
...
"userName": "james",
...
"_id": "james",
"description": "The new description for James",
...
}</computeroutput></screen>
<para>
To update a managed object with a PATCH request, use the
<literal>If-Match</literal> header. A PATCH request can add, remove, replace,
or increment an attribute value. A <literal>replace</literal> operation
replaces an existing value, or adds a value if no value exists.
</para>
<para>
The following example shows a patch request that updates a multi-valued
attribute by adding a new value. Note the dash <literal>-</literal> character
appended to the field name, which specifies that the value provided should be
added to the existing values. If the dash character is omitted, the provided
value replaces the existing values of that field.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-Match: *" \
--request PATCH \
--data '[
{
"operation": "add",
"field": "/roles/-",
"value": "managed/role/ldap"
}
]' \
"https://localhost:8443/openidm/managed/user/bjensen"</userinput>
</screen>
</section>
<section xml:id="rest-supported-delete">
<title>Deleting an Object</title>
<para>
A delete request is similar to an update request, and can optionally include
the HTTP <literal>If-Match</literal> header. To delete an object, specify
its ID in the request, for example:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request DELETE \
"https://localhost:8443/openidm/system/ldap/account/e81c7f15-2e6d-4c3c-8005-890101070dd9"</userinput>
<computeroutput>{
"_id": "e81c7f15-2e6d-4c3c-8005-890101070dd9"
} </computeroutput></screen>
</section>
<section xml:id="rest-supported-query">
<title>Querying Resources</title>
<para>
Resources can be queried using the <literal>GET</literal> method, with one of
the following query parameters:
</para>
<itemizedlist>
<para>
For queries on managed objects:
</para>
<listitem>
<para>
<literal>_queryId</literal> for arbitrary predefined, parameterized queries
</para>
</listitem>
<listitem>
<para>
<literal>_queryFilter</literal> for arbitrary filters, in common filter
notation
</para>
</listitem>
<listitem>
<para>
<literal>_queryExpression</literal> for client-supplied queries, in native
query format
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>
For queries on system objects:
</para>
<listitem>
<para>
<literal>_queryId=query-all-ids</literal> (the only supported predefined
query)
</para>
</listitem>
<listitem>
<para>
<literal>_queryFilter</literal> for arbitrary filters, in common filter
notation
</para>
</listitem>
</itemizedlist>
<para>
For additional information on queries, see the section on <link
xlink:href="integrators-guide#constructing-queries"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Constructing
Queries</citetitle></link>.
</para>
</section>
</section>
<section xml:id="rest-conditional-operations">
<title>Conditional Operations</title>
<para>The REST API fully supports conditional operations through the use of
the <literal>ETag</literal>, <literal>If-Match</literal> and
<literal>If-None-Match</literal> HTTP headers. The use of HTTP conditional
operations is the basis of OpenIDM's optimistic concurrency control system.
Clients should make requests conditional in order to prevent inadvertent
modification of the wrong version of an object.</para>
</section>
<section xml:id="rest-supported-methods">
<title>Supported Methods</title>
<para>
The managed object API uses standard HTTP methods to access managed objects.
</para>
<variablelist>
<varlistentry>
<term>GET</term>
<listitem>
<para>Retrieves a managed object in OpenIDM.</para>
<para>Example Request</para>
<programlisting language="http">
GET /openidm/managed/user/bdd793f8
...</programlisting>
<para>Example Response</para>
<programlisting language="http">
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-cache
Vary: Accept-Encoding, User-Agent
Set-Cookie: session-jwt=2sadf... afd5;Path=/
Expires: Thu, 01 Jan 2015 00:00:00 GMT
Content-Length: 1230
Server: Jetty(8.y.z-SNAPSHOT)
...
[<replaceable>JSON representation of the managed object</replaceable>]</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term>HEAD</term>
<listitem>
<para>Returns metainformation about a managed object in OpenIDM.</para>
<para>Example Request</para>
<programlisting language="http">
HEAD /openidm/managed/user/bdd793f8
...</programlisting>
<para>Example Response</para>
<programlisting language="http">
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123
ETag: "0"</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term>PUT</term>
<listitem>
<para>Creates or updates a managed object.</para>
<para>Example Request: Creating a new object</para>
<programlisting language="http">
PUT /openidm/managed/user/5752c0fd9509
Content-Type: application/json
Content-Length: 123
If-None-Match: *
...
[<replaceable>JSON representation of the managed object to create</replaceable>]</programlisting>
<para>Example Response: Creating a new object (success)</para>
<programlisting language="http">
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 45
ETag: "0"
...
[<replaceable>JSON representation containing metadata (underscore-prefixed) properties</replaceable>]</programlisting>
<para>
Example Response: Creating a new object without the
<literal>If-None-Match</literal> header
</para>
<programlisting language="http">
HTTP/1.1 404 Not Found
Content-Type: application/json
Content-Length: 83
...
[<replaceable>JSON representation of error</replaceable>]</programlisting>
<para>
Example Request: Updating an existing object
</para>
<programlisting language="http">
PUT /openidm/managed/user/5752c0fd9509
Content-Type: application/json
Content-Length: 123
If-Match: "1"
...
[<replaceable>JSON representation of managed object to update</replaceable>]</programlisting>
<para>Example Response: Updating an existing object (success)</para>
<programlisting language="http">
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 45
ETag: "2"
...
[<replaceable>JSON representation of updated object</replaceable>]</programlisting>
<para>Example Response: Updating an existing object when no version is
supplied</para>
<programlisting language="http">
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 89
ETag: "3"
...
[<replaceable>JSON representation of updated object</replaceable>]</programlisting>
<para>
Example Response: Updating an existing object when an invalid version is
supplied
</para>
<programlisting language="http">
HTTP/1.1 412 Precondition Required
Content-Type: application/json
Content-Length: 89
...
[<replaceable>JSON representation of error</replaceable>]</programlisting>
<para>
Example Response: Updating an existing object with
<literal>If-Match: *</literal></para>
<programlisting language="http">
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 45
ETag: "0"
...
[<replaceable>JSON representation of updated object</replaceable>]</programlisting>
<note xml:id="put-post-managed-objects">
<title>Should You Use PUT or POST to Create a Managed Object?</title>
<para>
You can use PUT and POST to create managed objects. To create a
managed object with a PUT, you would include the <literal>_id</literal>
in the request. If you create a managed object with a POST, the server
assigns the <literal>_id</literal> in the form of a UUID.
</para>
<para>
In some cases, you may want to use PUT, as POST is not idempotent. If you
can specify the <literal>_id</literal> to assign to the object, use PUT.
</para>
<para>
Alternatively, POST generates a server-assigned ID in the form of a
UUID. In some cases, you may prefer to use UUIDs in production, as a
POST can generate them easily in clustered environments.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term>POST</term>
<listitem>
<para>The POST method allows arbitrary actions to be performed on managed
objects. The <literal>_action</literal> query parameter defines the action
to be performed.</para>
<para>The <literal>create</literal> action is used to create a managed
object. Because POST is neither safe nor idempotent, PUT is the preferred
method of creating managed objects, and should be used if the client knows
what identifier it wants to assign the object. The response contains
the server-generated <literal>_id</literal> of the newly created managed
object.</para>
<para>The POST method create optionally accepts an <literal>_id</literal>
query parameter to specify the identifier to give the newly created
object. If an <literal>_id</literal> is not provided, the server selects
its own identifier.</para>
<para>The <literal>patch</literal> action is used to update one or more
attributes of a managed object, without replacing the entire object.</para>
<para>Example Create Request</para>
<programlisting language="http">
POST /openidm/managed/user?_action=create
Content-Type: application/json;charset=UTF-8
Content-Length: 123
...
[<replaceable>JSON representation of the managed object to create</replaceable>]</programlisting>
<para>Example Response</para>
<programlisting language="http">
HTTP/1.1 201 Created
Content-Type: application/json;charset=UTF-8
Cache-Control: no-cache
Location: https://<replaceable>Some_URI</replaceable>
...
[<replaceable>JSON representation containing metadata (underscore-prefixed) properties</replaceable>]</programlisting>
<para>Example Patch Request</para>
<programlisting language="http">
POST /openidm/managed/user?_action=patch
Content-Type: application/json;charset=UTF-8
Content-Length: 123
...
[<replaceable>JSON representation of the managed object to create</replaceable>]</programlisting>
<para>Example Response (success)</para>
<programlisting language="http">
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-cache
Set-Cookie: session-jwt=yAiYWxnIjogI;Path=/
...</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term>DELETE</term>
<listitem>
<para>Deletes a managed object.</para>
<para>Example Request</para>
<programlisting language="http">
DELETE /openidm/managed/user/c3471805b60f
If-Match: "0"
...</programlisting>
<para>Example Response (success)</para>
<programlisting language="http">
HTTP/1.1 200 OK
Content-Length: 405
Content-Type: application/json;charset=UTF-8
Etag: "4"
...
[<replaceable>JSON representation of the managed object that was deleted</replaceable>]</programlisting>
<para>
Example Response: Deleting an existing object when no version is supplied
</para>
<programlisting language="http">
HTTP/1.1 200 OK
Content-Length: 405
Content-Type: application/json;charset=UTF-8
Etag: "4"
...
[<replaceable>JSON representation of the managed object that was deleted</replaceable>]</programlisting>
<para>
Example Response: Deleting an existing object when an invalid version is
supplied
</para>
<programlisting language="http">
HTTP/1.1 412 Precondition Required
Content-Type: application/json;charset=UTF-8
Content-Length: 89
...
[<replaceable>JSON representation of error</replaceable>]</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term>PATCH</term>
<listitem>
<para>Performs a partial modification of a managed object.</para>
<para>See the <link xlink:show="new"
xlink:href="http://tools.ietf.org/html/draft-pbryan-json-patch-04">JSON
Patch Internet-Draft</link> for details.</para>
<para>Example Request</para>
<programlisting language="http">
PATCH /openidm/managed/user/5752c0fd9509
Content-Type: application/patch+json
Content-Length: 456
If-Match: "0"
...
[<replaceable>JSON representation of patch document to apply</replaceable>]</programlisting>
<para>Example Response (success)</para>
<programlisting language="http">
HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=1kke440cyv1vivbrid6ljso7b;Path=/
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: application/json; charset=UTF-8
ETag: "1"
...
{"_id":"5752c0fd9509","_rev":"2"}
</programlisting>
<para>Updating an existing object when no version is supplied (version
conflict)</para>
<programlisting language="http">
HTTP/1.1 409 Conflict
Content-Type: application/json;charset=UTF-8
Content-Length: 89
...
[<replaceable>JSON representation of error</replaceable>]</programlisting>
<para>Example Response: Updating an existing object when an invalid
version is supplied (version conflict)</para>
<programlisting language="http">
HTTP/1.1 412 Precondition Required
Content-Type: application/json;charset=UTF-8
Content-Length: 89
...
[<replaceable>JSON representation of error</replaceable>]</programlisting>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sample-rest-commands">
<title>REST Endpoints and Sample Commands</title>
<para>
This section describes the OpenIDM REST endpoints and provides
a number of sample commands that show the interaction with the REST
interface.
</para>
<section xml:id="rest-server-config">
<title>Managing the Server Configuration Over REST</title>
<para>
OpenIDM stores configuration objects in the repository, and exposes
them under the context path <literal>/openidm/config</literal>. Single instance
configuration objects are exposed under
<literal>/openidm/config/<replaceable>object-name</replaceable></literal>.
</para>
<para>
Multiple instance configuration objects are exposed under
<literal>/openidm/config/<replaceable>object-name</replaceable>/<replaceable>instance-name</replaceable></literal>.
The following table outlines these configuration objects and how they can
be accessed through the REST interface.
</para>
<informaltable pgwide="1">
<tgroup cols="3">
<colspec colname='c1' colwidth="50*"/>
<colspec colname='c2' colwidth="10*"/>
<colspec colname='c3' colwidth="40*"/>
<thead>
<row>
<entry>URI</entry>
<entry>HTTP Operation</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>/openidm/config</entry>
<entry>GET</entry>
<entry>Returns a list of configuration objects</entry>
</row>
<row>
<entry>/openidm/config/audit</entry>
<entry>GET</entry>
<entry>Returns the current logging configuration</entry>
</row>
<row>
<entry>/openidm/config/provisioner.openicf/<replaceable>provisioner-name</replaceable></entry>
<entry>GET</entry>
<entry>Returns the configuration of the specified connector</entry>
</row>
<row>
<entry>/openidm/config/router</entry>
<entry>PUT</entry>
<entry>Changes the router configuration. Modifications
are provided with the <literal>-data</literal> option,
in JSON format.</entry>
</row>
<row>
<entry>/openidm/config/<replaceable>object</replaceable></entry>
<entry>DELETE</entry>
<entry>Deletes the specified configuration object.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
OpenIDM supports REST mappings for create, read, update, query, and
delete of configuration objects. Currently OpenIDM does not support
patch operations for configuration objects.
</para>
<para>
For an example that displays the current configuration, the current
logging configuration, the configuration with an XML connector
provisioner, and how the configuration can be modified over the router,
see the section on <link xlink:href="integrators-guide#configuring-over-rest"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Configuring
OpenIDM Over REST</citetitle></link>.
</para>
<para>
One entry is returned for each configuration object. To obtain
additional information on the configuration object, include its
<literal>pid</literal> or <literal>_id</literal> in the URL. The
following example displays configuration information on the
<literal>sync</literal> object, based on OpenIDM using Sample 1.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/config/sync"</userinput>
<computeroutput>{
"mappings": [ {
"target" : "managed/user",
"correlationQuery" : {
"type" : "text/javascript",
"source" : "var query = {'_queryId' : 'for-userName', 'uid' : source.name};query;"
},
"properties" : [ {
"target" : "_id",
"source" : "_id"
}, {
"target" : "description",
"source" : "description"
}, {
"target" : "givenName",
"source" : "firstname"
}, {
"target" : "mail",
"source" : "email"
}, {
... </computeroutput></screen>
</section>
<section xml:id="managing-users-REST">
<title>Managing Users Over REST</title>
<para>
User objects are stored in the repository and are exposed under the context
path <literal>/managed/user</literal>. Many examples of REST calls related
to this context path exist throughout this document. The following table
lists available functionality associated with the
<literal>/managed/user</literal> context path.
</para>
<informaltable pgwide="1">
<tgroup cols="3">
<colspec colname='c1' colwidth="50*"/>
<colspec colname='c2' colwidth="10*"/>
<colspec colname='c3' colwidth="40*"/>
<thead>
<row>
<entry>URI</entry>
<entry>HTTP Operation</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>/openidm/managed/user?_queryId=query-all-ids</entry>
<entry>GET</entry>
<entry>List the IDs of all the managed users in the repository</entry>
</row>
<row>
<entry>/openidm/managed/user?_queryId=query-all</entry>
<entry>GET</entry>
<entry>List all info for the managed users in the repository</entry>
</row>
<row>
<entry>/openidm/managed/user?_queryFilter=<replaceable>filter</replaceable></entry>
<entry>GET</entry>
<entry>Query the managed user object with the defined filter. The value
of the query filter must be URL encoded.</entry>
</row>
<row>
<entry>/openidm/managed/user/<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Retrieve the JSON representation of a specific user</entry>
</row>
<row>
<entry>/openidm/managed/user/<replaceable>userName</replaceable></entry>
<entry>PUT</entry>
<entry>Create a new user</entry>
</row>
<row>
<entry>/openidm/managed/user/<replaceable>userName</replaceable></entry>
<entry>PUT</entry>
<entry>Update a user entry (replaces the entire entry)</entry>
</row>
<row>
<entry>/openidm/managed/user?_action=create</entry>
<entry>POST</entry>
<entry>Create a new user</entry>
</row>
<row>
<entry>/openidm/managed/user?_action=patch&amp;_queryId=for-userName&amp;uid=
<replaceable>userName</replaceable></entry>
<entry>POST</entry>
<entry>Update a user (can be used to replace the value of one or more
existing attributes)</entry>
</row>
<row>
<entry>/openidm/managed/user/<replaceable>userName</replaceable></entry>
<entry>PATCH</entry>
<entry>Update specified fields of a user entry</entry>
</row>
<row>
<entry>/openidm/managed/user/<replaceable>userName</replaceable></entry>
<entry>DELETE</entry>
<entry>Delete a user entry</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
The following example retrieves the JSON representation of all users stored
in the internal repository.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids"
</userinput></screen>
<para>
The following example queries the repository for managed users whose user
name is Smith.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryFilter=userName%20eq%20%22smith%22"
</userinput></screen>
<para>
The following example retrieves the JSON representation of a specified user.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/<replaceable>user_id</replaceable>"</userinput></screen>
<para>
To add a user without a specified ID, see the Installation Guide section on
<link xlink:role="http://docbook.org/xlink/role/olink"
xlink:href="install-guide#sample-adding-users-rest"><citetitle>Adding Users
Through REST</citetitle></link>.
</para>
<para>
The following example adds a user with a specific user ID.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request PUT \
--data '{
"userName":"james",
"sn":"Berg",
"givenName":"James",
"mail": "james@example.com",
"telephoneNumber": "082082082",
"password":"password"
}' \
"https://localhost:8443/openidm/managed/user/james"</userinput></screen>
<para>
The following example checks whether a user exists, then updates the user
entry. The command replaces the telephone number with the new data provided
in the request body.
</para>
<screen>$ <userinput>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 '[{
"operation":"replace",
"field":"/telephoneNumber",
"value":"1234567"
}]' \
"https://localhost:8443/openidm/managed/user?_action=patch&amp;_queryId=for-userName&amp;uid=<replaceable>id</replaceable>"</userinput>
</screen>
</section>
<section xml:id="managing-system-objects-REST">
<title>Managing System Objects Over REST</title>
<para>
System objects, that is, objects that are stored in remote systems, are
exposed under the <literal>/openidm/system</literal> context. OpenIDM
provides access to system objects over REST, as listed in the following
table.
</para>
<informaltable pgwide="1">
<tgroup cols="3">
<colspec colname='c1' colwidth="50*"/>
<colspec colname='c2' colwidth="10*"/>
<colspec colname='c3' colwidth="40*"/>
<thead>
<row>
<entry>URI</entry>
<entry>HTTP Operation</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>/openidm/system?_action=<replaceable>action-name</replaceable></entry>
<entry>POST</entry>
<entry>
<para>
<literal>_action=availableConnectors</literal> returns a list of the
connectors that are available in <literal>openidm/connectors</literal>
or in <literal>openidm/bundle</literal>.
</para>
<para>
<literal>_action=createCoreConfig</literal> takes the supplied
connector reference (<literal>connectorRef</literal>) and adds the
configuration properties required for that connector. This generates
a core connector configuration that you can use to create a full
configuration with the <literal>createFullConfig</literal> action.
</para>
<para>
<literal>_action=createFullConfig</literal> generates a complete
connector configuration, using the configuration properties from the
<literal>createCoreConfig</literal> action, and retrieving the object
types and operation options from the resource, to complete the
configuration.
</para>
<para>
<literal>_action=test</literal> returns a list of all remote systems,
with their status, and supported object types.
</para>
<para>
<literal>_action=testConfig</literal> validates the connector
configuration provided in the POST body.
</para>
<para>
<literal>_action=liveSync</literal> triggers a liveSync operation on
the specified source object.
</para>
<para>
<literal>_action=authenticate</literal> authenticates to the specified
system with the credentials provided.
</para>
</entry>
</row>
<row>
<entry>/openidm/system/<replaceable>system-name</replaceable>?_action=<replaceable>action-name</replaceable></entry>
<entry>POST</entry>
<entry>
<para>
<literal>_action=test</literal> tests the status of the specified
system.
</para>
</entry>
</row>
<row>
<entry>/openidm/system/<replaceable>system-name</replaceable>/<replaceable>system-object</replaceable>?_action=<replaceable>action-name</replaceable></entry>
<entry>POST</entry>
<entry>
<para>
<literal>_action=liveSync</literal> triggers a liveSync operation on
the specified system object.
</para>
<para>
<literal>_action=script</literal> runs the specified script on the
system object.
</para>
<para>
<literal>_action=authenticate</literal> authenticates to the specified
system object, with the provided credentials.
</para>
<para>
<literal>_action=create</literal> creates a new system object.
</para>
</entry>
</row>
<row>
<entry>/openidm/system/<replaceable>system-name</replaceable>/<replaceable>system-object</replaceable>?_queryId=query-all-ids</entry>
<entry>GET</entry>
<entry>Lists all IDs related to the specified system object, such as
users, and groups.</entry>
</row>
<row>
<entry>/openidm/system/<replaceable>system-name</replaceable>/<replaceable>system-object</replaceable>?_queryFilter=<replaceable>filter</replaceable></entry>
<entry>GET</entry>
<entry>Lists the item(s) associated with the query filter.</entry>
</row>
<row>
<entry>/openidm/system/<replaceable>system-name</replaceable>/<replaceable>system-object</replaceable>/<replaceable>id</replaceable></entry>
<entry>PUT</entry>
<entry>Creates a system object, or updates the system object, if it
exists (replaces the entire object).</entry>
</row>
<row>
<entry>/openidm/system/<replaceable>system-name</replaceable>/<replaceable>system-object</replaceable>/<replaceable>id</replaceable></entry>
<entry>DELETE</entry>
<entry>Deletes a system object.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<note>
<para>
When you create a system object with a PUT request (that is, specifying a
client-assigned ID), you should specify the ID in the URL only and not in
the JSON payload. If you specify a different ID in the URL and in the JSON
payload, the request will fail, with an error similar to the following:
</para>
<screen>
{
"code":500,
"reason":"Internal Server Error",
"message":"The uid attribute is not single value attribute."
}</screen>
<para>
The <literal>patch</literal> action is not supported on system objects.
</para>
</note>
<example>
<title>Returning a list of the available connector configurations</title>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"https://localhost:8443/openidm/system?_action=availableConnectors"</userinput></screen>
</example>
<example>
<title>Returning a list of remote systems, and their status</title>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"https://localhost:8443/openidm/system?_action=test"</userinput>
<computeroutput>[
{
"ok": true,
"displayName": "LDAP Connector",
"connectorRef": {
"bundleVersion": "[1.4.0.0,2.0.0.0)",
"bundleName": "org.forgerock.openicf.connectors.ldap-connector",
"connectorName": "org.identityconnectors.ldap.LdapConnector"
},
"objectTypes": [
"__ALL__",
"group",
"account"
],
"config": "config/provisioner.openicf/ldap",
"enabled": true,
"name": "ldap"
}
]</computeroutput></screen>
</example>
<example>
<title>Two options for running a liveSync operation on a specified system object</title>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"https://localhost:8443/openidm/system?_action=liveSync&amp;source=system/ldap/account"</userinput>
<computeroutput>{
"_rev": "1",
"_id": "SYSTEMLDAPACCOUNT",
"connectorData": {
"nativeType": "integer",
"syncToken": 0
}
}</computeroutput></screen>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"https://localhost:8443/openidm/system/ldap/account?_action=liveSync"</userinput>
<computeroutput>
{
"_rev": "2",
"_id": "SYSTEMLDAPACCOUNT",
"connectorData": {
"nativeType": "integer",
"syncToken": 0
}
} </computeroutput></screen>
</example>
<example>
<title>Running a script on a system object</title>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"https://localhost:8443/openidm/system/ldap/account?_action=script&amp;_scriptId=addUser"</userinput></screen>
</example>
<example>
<title>Authenticating to a system object</title>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"https://localhost:8443/openidm/system/ldap/account?_action=authenticate&amp;username=bjensen&amp;password=Passw0rd"</userinput>
<computeroutput>{
"_id": "fc252fd9-b982-3ed6-b42a-c76d2546312c"
}</computeroutput></screen>
</example>
<example>
<title>Creating a new system object</title>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "X-OpenIDM-Username: openidm-admin" \
--data '{
"cn":"James Smith",
"dn":"uid=jsmith,ou=people,dc=example,dc=com",
"uid":"jsmith",
"sn":"Smith",
"givenName":"James",
"mail": "jsmith@example.com",
"description":"Created by OpenIDM REST"}' \
--request POST \
"https://localhost:8443/openidm/system/ldap/account?_action=create"</userinput>
<computeroutput>{
"telephoneNumber":null,
"description":"Created by OpenIDM REST",
"mail":"jsmith@example.com",
"givenName":"James",
"cn":"James Smith",
"dn":"uid=jsmith,ou=people,dc=example,dc=com",
"uid":"jsmith",
"ldapGroups":[],
"sn":"Smith",
"_id":"07b46858-56eb-457c-b935-cfe6ddf769c7"
} </computeroutput></screen>
</example>
<example>
<title>Renaming a system object</title>
<para>
You can rename a system object simply by supplying a new naming attribute
value in a PUT request. The PUT request replaces the entire object. The
naming attribute depends on the external resource.
</para>
<para>
The following example renames an object on an LDAP server, by changing the
DN of the LDAP object (effectively performing a modDN operation on that
object).
</para>
<para>
The example renames the user created in the previous example.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "If-Match: *" \
--data '{
"cn":"James Smith",
"dn":"uid=jimmysmith,ou=people,dc=example,dc=com",
"uid":"jimmysmith",
"sn":"Smith",
"givenName":"James",
"mail": "jsmith@example.com"}' \
--request PUT \
"https://localhost:8443/openidm/system/ldap/account/07b46858-56eb-457c-b935-cfe6ddf769c7"</userinput>
<computeroutput>{
"mail":"jsmith@example.com",
"cn":"James Smith",
"sn":"Smith",
"dn":"uid=jimmysmith,ou=people,dc=example,dc=com",
"ldapGroups":[],
"telephoneNumber":null,
"description":"Created by OpenIDM REST",
"givenName":"James",
"uid":"jimmysmith",
"_id":"07b46858-56eb-457c-b935-cfe6ddf769c7"
}</computeroutput> </screen>
</example>
<example>
<title>List the IDs associated with a specific system object</title>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "X-OpenIDM-Username: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/system/ldap/account?_queryId=query-all-ids"</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 3,
"result": [
{
"dn": "uid=jdoe,ou=People,dc=example,dc=com",
"_id": "1ff2e78f-4c4c-300c-b8f7-c2ab160061e0"
},
{
"dn": "uid=bjensen,ou=People,dc=example,dc=com",
"_id": "fc252fd9-b982-3ed6-b42a-c76d2546312c"
},
{
"dn": "uid=jimmysmith,ou=people,dc=example,dc=com",
"_id": "07b46858-56eb-457c-b935-cfe6ddf769c7"
}
]
}</computeroutput></screen>
</example>
</section>
<section xml:id="managing-workflows-over-REST">
<title>Managing Workflows Over REST</title>
<para>
Workflow objects are exposed under the <literal>/openidm/workflow</literal>
context. OpenIDM provides access to the workflow module over REST, as listed
in the following table.
</para>
<informaltable pgwide="1">
<tgroup cols="3">
<colspec colname='c1' colwidth="50*"/>
<colspec colname='c2' colwidth="10*"/>
<colspec colname='c3' colwidth="40*"/>
<thead>
<row>
<entry>URI</entry>
<entry>HTTP Operation</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>/openidm/workflow/processdefinition?_queryId=<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Lists workflow definitions based on filtering criteria</entry>
</row>
<row>
<entry>/openidm/workflow/processdefinition/<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Returns detailed information about the specified process definition</entry>
</row>
<row>
<entry>/openidm/workflow/processinstance?_queryId=query-all-ids</entry>
<entry>GET</entry>
<entry>Lists the available running workflows, by IDs</entry>
</row>
<row>
<entry>/openidm/workflow/processinstance/<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Provides detailed information of a running process instance</entry>
</row>
<row>
<entry>/openidm/workflow/processdefinition/<replaceable>id</replaceable>/taskdefinition</entry>
<entry>GET</entry>
<entry>Returns detailed information about the task definition, when you
include an <replaceable>id</replaceable> or a query for all IDs,
<literal>?_queryId=query-all-ids</literal></entry>
</row>
<row>
<entry>/openidm/workflow/taskinstance?_queryId=query-all-ids</entry>
<entry>GET</entry>
<entry>Lists all active tasks</entry>
</row>
<row>
<entry>/openidm/workflow/taskinstance?_queryId=filteredQuery&amp;<replaceable>filter
</replaceable></entry>
<entry>GET</entry>
<entry>Lists the tasks according to the specified filter</entry>
</row>
<row>
<entry>/openidm/workflow/processinstance?_action=create</entry>
<entry>POST</entry>
<entry>Start a new workflow. Parameters are included in the request body.</entry>
</row>
<row>
<entry>/openidm/workflow/taskinstance/<replaceable>id</replaceable></entry>
<entry>PUT</entry>
<entry>Update task data</entry>
</row>
<row>
<entry>/openidm/workflow/processinstance/<replaceable>id</replaceable></entry>
<entry>DELETE</entry>
<entry>Stops a process instance</entry>
</row>
<row>
<entry>/openidm/workflow/taskinstance/<replaceable>id</replaceable>?_action=claim</entry>
<entry>POST</entry>
<entry>Claim or complete a task. Parameters are included in the request body.
Specifically for user tasks, a user can <emphasis>claim</emphasis> a specific
task, which will then be assigned to that user.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>The following examples list the defined workflows. For a workflow to
appear in this list, the corresponding workflow definition must be in the
<literal>openidm/workflow</literal> directory.</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processdefinition?_queryId=query-all-ids"</userinput></screen>
<para>Depending on the defined workflows, the output will be something like
the following:</para>
<screen>{
"result":[ {
"tenantId" : "",
"candidateStarterGroupIdExpressions" : [ ],
"candidateStarterUserIdExpressions" : [ ],
"participantProcess" : null,
...
} ],
"resultCount" : 1,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</screen>
<para>The following example invokes a workflow named "myWorkflow". The
<literal>foo</literal> parameter is given the value <literal>bar</literal>
in the workflow invocation.</para>
<screen>$ <userinput>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 '{
"key":"contractorOnboarding",
"foo":"bar"
}' \
"https://localhost:8443/openidm/workflow/processinstance?_action=create"</userinput></screen>
</section>
<section xml:id="managing-scanned-REST">
<title>Managing Scanned Tasks Over REST</title>
<para>
OpenIDM provides a task scanning mechanism that enables you
to perform a batch scan for a specified date in OpenIDM data, on a
scheduled interval, and then to execute a task when this date is
reached. For more information about scanned tasks, see <link
xlink:href="integrators-guide#task-scanner"
xlink:role="http://docbook.org/xlink/role/olink">
<citetitle>Scanning Data to Trigger Tasks</citetitle></link>.</para>
<para>OpenIDM provides REST access to the task scanner, as listed
in the following table.</para>
<informaltable pgwide="1">
<tgroup cols="3">
<colspec colname='c1' colwidth="50*"/>
<colspec colname='c2' colwidth="10*"/>
<colspec colname='c3' colwidth="40*"/>
<thead>
<row>
<entry>URI</entry>
<entry>HTTP Operation</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>/openidm/taskscanner</entry>
<entry>GET</entry>
<entry>Lists the all scanning tasks, past and present.</entry>
</row>
<row>
<entry>/openidm/taskscanner/<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Lists details of the given task.</entry>
</row>
<row>
<entry>/openidm/taskscanner?_action=execute&amp;name=<replaceable>name</replaceable></entry>
<entry>POST</entry>
<entry>Triggers the specified task scan run.</entry>
</row>
<row>
<entry>/openidm/taskscanner/<replaceable>id</replaceable>?_action=cancel</entry>
<entry>POST</entry>
<entry>Cancels the specified task scan run.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section xml:id="accessing-log-REST">
<title>Accessing Log Entries Over REST</title>
<para>
You can interact with the audit and activity logs over REST, as
shown in the following table.</para>
<informaltable pgwide="1">
<tgroup cols="3">
<colspec colname='c1' colwidth="50*"/>
<colspec colname='c2' colwidth="10*"/>
<colspec colname='c3' colwidth="40*"/>
<thead>
<row>
<entry>URI</entry>
<entry>HTTP Operation</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>/openidm/audit/recon</entry>
<entry>GET</entry>
<entry>Displays the reconciliation audit log</entry>
</row>
<row>
<entry>/openidm/audit/recon/<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Reads a specific reconciliation audit log entry</entry>
</row>
<row>
<entry>/openidm/audit/recon?_queryId=audit-by-recon-id&amp;reconId=<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Queries the audit log for a particular reconciliation operation</entry>
</row>
<row>
<entry>/openidm/audit/recon?_queryId=audit-by-recon-id-situation&amp;situation=
<replaceable>situation</replaceable>&amp;reconId=<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Queries the reconciliation audit log for a specific reconciliation situation</entry>
</row>
<row>
<entry>/openidm/audit/activity</entry>
<entry>GET</entry>
<entry>Displays the activity log</entry>
</row>
<row>
<entry>/openidm/audit/activity/<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Returns activity information for a specific action</entry>
</row>
<row>
<entry>/openidm/audit/activity?_queryId=audit-by-activity-parent-action&amp;parentActionId=<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Queries the activity log for the details of an action</entry>
</row>
<row>
<entry>/openidm/audit/access</entry>
<entry>GET</entry>
<entry>Displays the full list of auditable actions.</entry>
</row>
<row>
<entry>/openidm/audit/access/<replaceable>id</replaceable></entry>
<entry>GET</entry>
<entry>Displays information on the specific audit item.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section xml:id="recon-over-REST">
<title>Managing Reconciliation Operations Over REST</title>
<para>
You can interact with the reconciliation engine over REST,
as shown in the following table.</para>
<informaltable pgwide="1">
<tgroup cols="3">
<colspec colname='c1' colwidth="50*"/>
<colspec colname='c2' colwidth="10*"/>
<colspec colname='c3' colwidth="40*"/>
<thead>
<row>
<entry>URI</entry>
<entry>HTTP Operation</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>/openidm/recon</entry>
<entry>GET</entry>
<entry>Lists all completed reconciliation runs</entry>
</row>
<row>
<entry>/openidm/recon?_action=recon&amp;mapping=<replaceable>mapping-name
</replaceable></entry>
<entry>POST</entry>
<entry>Launches a reconciliation run with the specified mapping</entry>
</row>
<row>
<entry>/openidm/recon/<replaceable>id</replaceable>?_action=cancel</entry>
<entry>POST</entry>
<entry>Cancels the specified reconciliation run</entry>
</row>
<row>
<entry>/openidm/system/<replaceable>datastore</replaceable>
account?_action=liveSync</entry>
<entry>POST</entry>
<entry>Calls a LiveSync operation.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
The following example runs a reconciliation action, with the mapping
<literal>systemHrdb_managedUser</literal>, defined in the <filename>sync.json
</filename> file.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemHrdb_managedUser"</userinput></screen>
</section>
<section xml:id="repo-REST">
<title>Managing the Repository over REST</title>
<para>
You can interact with the repository engine over REST, as shown in the
following table.
</para>
<informaltable pgwide="1">
<tgroup cols="3">
<colspec colname='c1' colwidth="50*"/>
<colspec colname='c2' colwidth="10*"/>
<colspec colname='c3' colwidth="40*"/>
<thead>
<row>
<entry>URI</entry>
<entry>HTTP Operation</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>/openidm/repo/synchronisation/deadLetterQueue/<replaceable>resource</replaceable>?_queryId=query-all-ids</entry>
<entry>GET</entry>
<entry>Lists any failed synchronisation records for that resource, that
have been placed in the dead letter queue.</entry>
</row>
<row>
<entry>/openidm/repo/link?_queryId=query-all-ids</entry>
<entry>GET</entry>
<entry>Lists entries in the links table</entry>
</row>
<row>
<entry>/openidm/repo/internal/user?_queryId=query-all-ids</entry>
<entry>GET</entry>
<entry>Lists the internal users</entry>
</row>
<row>
<entry>/openidm/repo/internal/user/<replaceable>username</replaceable></entry>
<entry>PUT</entry>
<entry>Enables you to change the username or password of an internal user</entry>
</row>
<row>
<entry>/openidm/repo?_action=updateDbCredentials</entry>
<entry>POST</entry>
<entry>Enables you to change the database username and password, in the
case of an OrientDB repository</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
For examples of queries on the <literal>repo/</literal> endpoint, see
<link xlink:show="new" xlink:href="integrators-guide#repo-over-rest"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Interacting
With the Repository Over REST</citetitle></link>.
</para>
</section>
</section>
<section xml:id="http-status-codes">
<title>HTTP Status Codes</title>
<para>The OpenIDM REST API returns the standard HTTP response codes, as
described in the following table.</para>
<informaltable>
<tgroup cols="2">
<colspec colname='c1' colwidth="40*"/>
<colspec colname='c2' colwidth="60*"/>
<thead>
<row>
<entry>HTTP Status</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>200 OK</entry>
<entry>The request was successfully completed. If this request created a
new resource that is addressable with a URI, and a response body is
returned containing a representation of the new resource, a 200 status
will be returned with a Location header containing the canonical URI for
the newly created resource.</entry>
</row>
<row>
<entry>201 Created</entry>
<entry>A request that created a new resource was completed. A
representation of the new resource is returned. A
Location header containing the canonical URI for the newly created resource
should also be returned.</entry>
</row>
<row>
<entry>202 Accepted</entry>
<entry>The request has been accepted for processing, but the processing
has not been completed.</entry>
</row>
<row>
<entry>204 No Content</entry>
<entry>The server fulfilled the request, but does not need to return a
response message body.</entry>
</row>
<row>
<entry>400 Bad Request</entry>
<entry>The request could not be processed because it contains missing or
invalid information.</entry>
</row>
<row>
<entry>401 Unauthorized</entry>
<entry>The authentication credentials included with this request are
missing or invalid.</entry>
</row>
<row>
<entry>403 Forbidden</entry>
<entry>The server recognized your credentials, but you do not possess
authorization to perform this request.</entry>
</row>
<row>
<entry>404 Not Found</entry>
<entry>The request specified a URI of a resource that does not exist.</entry>
</row>
<row>
<entry>405 Method Not Allowed</entry>
<entry>The HTTP verb specified in the request (DELETE, GET, HEAD, POST, PUT)
is not supported for this request URI.</entry>
</row>
<row>
<entry>406 Not Acceptable</entry>
<entry>The resource identified by this request is not capable of generating
a representation corresponding to one of the media types in the Accept
header of the request.</entry>
</row>
<row>
<entry>409 Conflict</entry>
<entry>A creation or update request could not be completed, because it would
cause a conflict in the current state of the resources supported by the
server (for example, an attempt to create a new resource with a unique
identifier already assigned to some existing resource).</entry>
</row>
<row>
<entry>500 Internal Server Error</entry>
<entry>The server encountered an unexpected condition which prevented it
from fulfilling the request.</entry>
</row>
<row>
<entry>501 Not Implemented</entry>
<entry>The server does not (currently) support the functionality required
to fulfill the request.</entry>
</row>
<row>
<entry>503 Service Unavailable</entry>
<entry>The server is currently unable to handle the request due to
temporary overloading or maintenance of the server.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<!--TODO Fix for OPENIDM-2339
<section xml:id="CRESTvsREST">
<title>Differences between the CREST API and a Generic REST API</title>
<para>
The main difference between a CREST-based REST API and a generic REST API is
that CREST is inherently recognizable by all ForgeRock products.
As such, you can leverage CREST resources in your scripts, to create
CREST requests.
</para>
<para>
For example, to write a <literal>CREATE</literal> request in CREST, you
might use a Groovy script similar to the following:
</para>
<programlisting>
CreateRequest request = Requests.newCreateRequest(objectClassInfo.resourceContainer, new JsonValue(user))
Resource resource = connection.create(new RootContext(), request)
</programlisting>
<para>
The preceding code excerpt creates a <emphasis>formatted</emphasis> create
REST request, and does the HTTP request based on that format. With a generic
REST API, the corresponding Groovy script would need to build an HTTP request
manually, based on some defined REST API. This manual creation would require
setting the method, path, content and other HTTP request properties to make
the REST call.
</section> -->
</appendix>