6443N/A<?xml version="1.0" encoding="UTF-8"?>
6443N/A<!--
6443N/A ! CCPL HEADER START
6443N/A !
6443N/A ! This work is licensed under the Creative Commons
6443N/A ! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
6443N/A ! To view a copy of this license, visit
6443N/A ! http://creativecommons.org/licenses/by-nc-nd/3.0/
6443N/A ! or send a letter to Creative Commons, 444 Castro Street,
6443N/A ! Suite 900, Mountain View, California, 94041, USA.
6443N/A !
6443N/A ! You can also obtain a copy of the license at
6443N/A ! trunk/opendj3/legal-notices/CC-BY-NC-ND.txt.
6443N/A ! See the License for the specific language governing permissions
6443N/A ! and limitations under the License.
6443N/A !
6443N/A ! If applicable, add the following below this CCPL HEADER, with the fields
6443N/A ! enclosed by brackets "[]" replaced with your own identifying information:
6443N/A ! Portions Copyright [yyyy] [name of copyright owner]
6443N/A !
6443N/A ! CCPL HEADER END
6443N/A !
7321N/A ! Copyright 2013-2015 ForgeRock AS.
6443N/A !
6443N/A-->
6443N/A<chapter xml:id='chap-rest-operations'
6443N/A xmlns='http://docbook.org/ns/docbook' version='5.0' xml:lang='en'
6443N/A xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
7086N/A xsi:schemaLocation='http://docbook.org/ns/docbook
7086N/A http://docbook.org/xml/5.0/xsd/docbook.xsd'
7086N/A xmlns:xlink='http://www.w3.org/1999/xlink'>
6443N/A <title>Performing RESTful Operations</title>
6443N/A <indexterm><primary>HTTP</primary></indexterm>
6443N/A <indexterm><primary>JSON</primary></indexterm>
6443N/A <indexterm><primary>REST</primary></indexterm>
6443N/A
7255N/A <para>
7255N/A OpenDJ lets you access directory data as
7255N/A <link xlink:show="new" xlink:href="http://json.org">JSON</link>
7255N/A resources over HTTP.
7255N/A This chapter demonstrates basic RESTful client operations
7255N/A by using the default configuration
7255N/A and sample directory data imported into OpenDJ from
7255N/A <link
7255N/A xlink:show="new"
7255N/A xlink:href="http://opendj.forgerock.org/Example.ldif"
7255N/A >Example.ldif</link>.
7255N/A </para>
7097N/A
7097N/A <para>
7097N/A Before trying the examples, enable HTTP access to
7097N/A OpenDJ directory server as described in procedure,
7097N/A <link
7097N/A xlink:show="new"
7097N/A xlink:href="admin-guide#setup-rest2ldap-connection-handler"
7097N/A xlink:role="http://docbook.org/xlink/role/olink"
7097N/A ><citetitle>To Set Up REST Access to OpenDJ Directory Server</citetitle></link>.
7097N/A The examples in this chapter use HTTP,
7097N/A but the procedure also shows how to set up HTTPS access to the server.
7097N/A </para>
6443N/A
7321N/A <para>Interface stability: <link xlink:href="reference#interface-stability"
6443N/A xlink:show="new" xlink:role="http://docbook.org/xlink/role/olink"
6443N/A >Evolving</link></para>
6443N/A
6443N/A <section xml:id="understand-rest">
6443N/A <title>Understanding the OpenDJ REST API</title>
6443N/A
6443N/A <para>The OpenDJ REST API is built on a common ForgeRock HTTP-based REST API
6443N/A for interacting with JSON Resources. APIs built on this common layer all let
6443N/A you perform the following operations.</para>
6443N/A
6443N/A <variablelist>
6443N/A <varlistentry>
6443N/A <term><link linkend="create-rest">Create</link></term>
6443N/A <listitem>
6443N/A <para>Add a resource that does not yet exist</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><link linkend="read-rest">Read</link></term>
6443N/A <listitem>
6443N/A <para>Retrieve a single resource</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><link linkend="update-rest">Update</link></term>
6443N/A <listitem>
6443N/A <para>Replace an existing resource</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><link linkend="delete-rest">Delete</link></term>
6443N/A <listitem>
6443N/A <para>Remove an existing resource</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><link linkend="patch-rest">Patch</link></term>
6443N/A <listitem>
6443N/A <para>Modify part of an existing resource</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><link linkend="action-rest">Action</link></term>
6443N/A <listitem>
6443N/A <para>Perform a predefined action</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><link linkend="query-rest">Query</link></term>
6443N/A <listitem>
6443N/A <para>List a set of resources</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A </variablelist>
6443N/A
6443N/A <para>The present implementation in OpenDJ maps JSON resources onto LDAP
6443N/A entries, meaning REST clients can in principle do just about anything an
6443N/A LDAP client can do with directory data.</para>
6443N/A
6443N/A <variablelist>
6443N/A <para>In addition to query string parameters that depend on the operation,
6443N/A the examples in this chapter make use of the following parameters that
6443N/A apply to the JSON resource returned for all operations.</para>
6443N/A <varlistentry>
6443N/A <term><literal>_fields=<replaceable>field</replaceable>[,&#8230;]</literal></term>
6443N/A <listitem>
6443N/A <para>Retain only the specified fields in the JSON resource returned.</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A <varlistentry>
6443N/A <term><literal>_prettyPrint=true|false</literal></term>
6443N/A <listitem>
6443N/A <para>Make the JSON resource returned easy for humans to read.</para>
7158N/A
7158N/A <para>
7158N/A This parameter is used though not shown in most examples that follow.
7158N/A </para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A </variablelist>
6443N/A </section>
6443N/A
6443N/A <section xml:id="authenticate-rest">
6443N/A <title>Authenticating Over REST</title>
6443N/A
6443N/A <para>When you first try to get a resource that you can read as an LDAP
6443N/A entry with an anonymous search, you might be surprised that you must
6443N/A authenticate.</para>
6443N/A
7097N/A <screen>
7158N/A$ <userinput>curl http://opendj.example.com:8080/users/bjensen</userinput>
7097N/A<computeroutput>{
6443N/A "code" : 401,
6443N/A "reason" : "Unauthorized",
6443N/A "message" : "Unauthorized"
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>HTTP status code 401 tells your HTTP client that the request requires
6443N/A user authentication. You can change this behavior by setting the HTTP
6443N/A connection handler property, <literal>authentication-required</literal>,
6443N/A to <literal>false</literal>.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>dsconfig \
7097N/A set-connection-handler-prop \
7097N/A --hostname opendj.example.com \
7097N/A --port 4444 \
7097N/A --bindDN "cn=Directory Manager" \
7097N/A --bindPassword password \
7097N/A --handler-name "HTTP Connection Handler" \
7097N/A --set authentication-required:false \
7097N/A --no-prompt \
7097N/A --trustAll</userinput>
7097N/A </screen>
6443N/A
6443N/A <para>Out of the box both the HTTP Connection Handler and also the REST LDAP
6443N/A gateway are configured to allow HTTP Basic authentication and HTTP header
6443N/A based authentication in the style of OpenIDM. The authentication mechanisms
6443N/A translate HTTP authentication to LDAP authentication on the directory server
6443N/A side.</para>
6443N/A
6443N/A <para>When you install OpenDJ either with generated sample user entries or
6443N/A with data from <link xlink:href="http://opendj.forgerock.org/Example.ldif"
6443N/A xlink:show="new">Example.ldif</link>, the relative distinguished name
6443N/A attribute for the sample user entries is the user ID (<literal>uid</literal>)
6443N/A attribute. For example, the DN and user ID for Babs Jensen are as
6443N/A follows.</para>
6443N/A
7097N/A <programlisting language="ldif">
7097N/Adn: uid=bjensen,ou=People,dc=example,dc=com
7097N/Auid: bjensen
7097N/A </programlisting>
6443N/A
7197N/A <para>
7197N/A Given this pattern in the user entries,
7197N/A the default REST to LDAP configuration assumes that the user name
7197N/A on the HTTP side is the value of the user ID,
7197N/A and that user entries can be found directly under
7197N/A <literal>ou=People,dc=example,dc=com</literal>.<footnote>
7197N/A <para>
7197N/A In general, REST to LDAP mappings require
7197N/A that LDAP entries mapped to JSON resources
7197N/A be immediate subordinates of the mapping's baseDN.
7197N/A </para>
7197N/A </footnote>
7197N/A In other words, Babs Jensen authenticates as <literal>bjensen</literal>
7197N/A (password: <literal>hifalutin</literal>) over HTTP.
7197N/A This is mapped for an LDAP bind to the bind DN
7197N/A <literal>uid=bjensen,ou=People,dc=example,dc=com</literal>.
7197N/A </para>
6443N/A
6443N/A <para>With HTTP Basic authentication, it looks like this.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user bjensen:hifalutin \
7158N/A http://opendj.example.com:8080/users/bjensen</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "0000000016cbb68c",
6443N/A ...
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>Or, using the HTTP Basic
6443N/A <replaceable>username</replaceable>:<replaceable>password</replaceable>@ form
6443N/A in the URL, it looks like this.</para>
6443N/A
7158N/A <screen>
7097N/A$ <userinput>curl \
7158N/A http://bjensen:hifalutin@opendj.example.com:8080/users/bjensen</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "0000000016cbb68c",
6443N/A ...
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>With HTTP header based authentication, it looks like this.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --header "X-OpenIDM-Username: bjensen" \
7097N/A --header "X-OpenIDM-Password: hifalutin" \
7158N/A http://opendj.example.com:8080/users/bjensen</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "0000000016cbb68c",
6443N/A ...
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>If your directory data are laid out differently, or if your user names
6443N/A are email addresses rather than user IDs for example, then you must update
6443N/A the configuration in order for authentication to work.</para>
6443N/A
6443N/A <para>The REST LDAP gateway can also translate HTTP user name and password
6443N/A authentication to PLAIN SASL authentication on the LDAP side. Moreover, the
6443N/A gateway can fall back to proxied authorization as necessary, using a root DN
6443N/A authenticated connection to LDAP servers. See <link xlink:show="new"
7321N/A xlink:href="reference#appendix-rest2ldap"
6443N/A xlink:role="http://docbook.org/xlink/role/olink"><citetitle>REST LDAP
6443N/A Configuration</citetitle></link> for details on all configuration
6443N/A choices.</para>
6443N/A </section>
6443N/A
6443N/A <section xml:id="create-rest">
6443N/A <title>Creating Resources</title>
6443N/A
6443N/A <para>There are two ways to create resources.</para>
6443N/A
6443N/A <itemizedlist>
6443N/A <listitem>
6443N/A <para>To create a resource using an ID that you specify, perform an HTTP PUT
6443N/A request with headers <literal>Content-Type: application/json</literal> and
6443N/A <literal>If-None-Match: *</literal>, and the JSON content of your
6443N/A resource.</para>
6443N/A
6443N/A <para>The following example creates a new user entry with ID
6443N/A <literal>newuser</literal>.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --request PUT \
7097N/A --user kvaughan:bribery \
7097N/A --header "Content-Type: application/json" \
7097N/A --header "If-None-Match: *" \
7142N/A --data '{
7142N/A "_id": "newuser",
7142N/A "contactInformation": {
7142N/A "telephoneNumber": "+1 408 555 1212",
7142N/A "emailAddress": "newuser@example.com"
7142N/A },
7142N/A "name": {
7142N/A "familyName": "New",
7142N/A "givenName": "User"
7142N/A },
7142N/A "displayName": "New User",
7142N/A "manager": [
7142N/A {
7142N/A "_id": "kvaughan",
7142N/A "displayName": "Kirsten Vaughan"
7142N/A }
7142N/A ]
7097N/A }' \
7158N/A http://opendj.example.com:8080/users/newuser</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "000000005b337348",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1212",
6443N/A "emailAddress" : "newuser@example.com"
6443N/A },
6443N/A "_id" : "newuser",
6443N/A "name" : {
6443N/A "familyName" : "New",
6443N/A "givenName" : "User"
6443N/A },
6443N/A "userName" : "newuser@example.com",
6443N/A "displayName" : "New User",
6443N/A "meta" : {
6443N/A "created" : "2013-04-11T09:58:27Z"
6443N/A },
6443N/A "manager" : [ {
6443N/A "_id" : "kvaughan",
6443N/A "displayName" : "Kirsten Vaughan"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A
6443N/A <listitem>
6443N/A <para>To create a resource letting the server choose the ID, perform an HTTP
6443N/A POST with <literal>_action=create</literal> as described in
6443N/A <xref linkend="action-rest" />.</para>
6443N/A </listitem>
6443N/A </itemizedlist>
6443N/A </section>
6443N/A
6443N/A <section xml:id="read-rest">
6443N/A <title>Reading a Resource</title>
6443N/A
6443N/A <para>To read a resource, perform an HTTP GET.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --request GET \
7097N/A --user kvaughan:bribery \
7158N/A http://opendj.example.com:8080/users/newuser</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "000000005b337348",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1212",
6443N/A "emailAddress" : "newuser@example.com"
6443N/A },
6443N/A "_id" : "newuser",
6443N/A "name" : {
6443N/A "familyName" : "New",
6443N/A "givenName" : "User"
6443N/A },
6443N/A "userName" : "newuser@example.com",
6443N/A "displayName" : "New User",
6443N/A "meta" : {
6443N/A "created" : "2013-04-11T09:58:27Z"
6443N/A },
6443N/A "manager" : [ {
6443N/A "_id" : "kvaughan",
6443N/A "displayName" : "Kirsten Vaughan"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </section>
6443N/A
6443N/A <section xml:id="update-rest">
6443N/A <title>Updating Resources</title>
6443N/A
6443N/A <para>To update a resource, perform an HTTP PUT with the changes to the
6443N/A resource. For read-only fields, either include unmodified versions, or omit
6443N/A them from your updated version.</para>
6443N/A
6443N/A <para>The following example adds a manager for Sam Carter.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --request PUT \
7097N/A --user kvaughan:bribery \
7097N/A --header "Content-Type: application/json" \
7142N/A --data '{
7142N/A "contactInformation": {
7142N/A "telephoneNumber": "+1 408 555 4798",
7142N/A "emailAddress": "scarter@example.com"
7142N/A },
7142N/A "name": {
7142N/A "familyName": "Carter",
7142N/A "givenName": "Sam"
7142N/A },
7142N/A "userName": "scarter@example.com",
7142N/A "displayName": "Sam Carter",
7142N/A "groups": [
7142N/A {
7142N/A "_id": "Accounting Managers"
7142N/A }
7142N/A ],
7142N/A "manager": [
7142N/A {
7142N/A "_id": "trigden",
7142N/A "displayName": "Torrey Rigden"
7142N/A }
7142N/A ]
7097N/A }' \
7158N/A http://opendj.example.com:8080/users/scarter</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "00000000a1923db2",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 4798",
6443N/A "emailAddress" : "scarter@example.com"
6443N/A },
6443N/A "_id" : "scarter",
6443N/A "name" : {
6443N/A "familyName" : "Carter",
6443N/A "givenName" : "Sam"
6443N/A },
6443N/A "userName" : "scarter@example.com",
6443N/A "displayName" : "Sam Carter",
6443N/A "manager" : [ {
6443N/A "_id" : "trigden",
6443N/A "displayName" : "Torrey Rigden"
6443N/A } ],
6443N/A "meta" : {
6443N/A "lastModified" : "2013-04-12T07:42:34Z"
6443N/A },
6443N/A "groups" : [ {
6443N/A "_id" : "Accounting Managers"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>To update a resource only if the resource matches a particular version,
6443N/A use an <literal>If-Match: <replaceable>revision</replaceable></literal>
6443N/A header.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A http://opendj.example.com:8080/users/scarter?_fields=_rev</userinput>
7097N/A<computeroutput>{"_rev":"00000000b017c5b8"}</computeroutput>
7097N/A
7097N/A$ <userinput>curl \
7097N/A --request PUT \
7097N/A --user kvaughan:bribery \
7097N/A--header "If-Match: 00000000b017c5b8" \
7097N/A --header "Content-Type: application/json" \
7142N/A --data '{
7142N/A "contactInformation": {
7142N/A "telephoneNumber": "+1 408 555 1212",
7142N/A "emailAddress": "scarter@example.com"
7142N/A },
7142N/A "name": {
7142N/A "familyName": "Carter",
7142N/A "givenName": "Sam"
7142N/A },
7142N/A "userName": "scarter@example.com",
7142N/A "displayName": "Sam Carter",
7142N/A "groups": [
7142N/A {
7142N/A "_id": "Accounting Managers"
7142N/A }
7142N/A ],
7142N/A "manager": [
7142N/A {
7142N/A "_id": "trigden",
7142N/A "displayName": "Torrey Rigden"
7142N/A }
7142N/A ]
7097N/A }' \
7158N/A http://opendj.example.com:8080/users/scarter</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "00000000a1ee3da3",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1212",
6443N/A "emailAddress" : "scarter@example.com"
6443N/A },
6443N/A "_id" : "scarter",
6443N/A "name" : {
6443N/A "familyName" : "Carter",
6443N/A "givenName" : "Sam"
6443N/A },
6443N/A "userName" : "scarter@example.com",
6443N/A "displayName" : "Sam Carter",
6443N/A "meta" : {
6443N/A "lastModified" : "2013-04-12T07:47:45Z"
6443N/A },
6443N/A "groups" : [ {
6443N/A "_id" : "Accounting Managers"
6443N/A } ],
6443N/A "manager" : [ {
6443N/A "_id" : "trigden",
6443N/A "displayName" : "Torrey Rigden"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </section>
6443N/A
6443N/A <section xml:id="delete-rest">
6443N/A <title>Deleting Resources</title>
6443N/A
6443N/A <para>To delete a resource, perform an HTTP DELETE on the resource URL.
6443N/A On success, the operation returns the resource you deleted.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --request DELETE \
7097N/A --user kvaughan:bribery \
7158N/A http://opendj.example.com:8080/users/newuser</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "000000003a5f3cb2",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1212",
6443N/A "emailAddress" : "newuser@example.com"
6443N/A },
6443N/A "_id" : "newuser",
6443N/A "name" : {
6443N/A "familyName" : "New",
6443N/A "givenName" : "User"
6443N/A },
6443N/A "userName" : "newuser@example.com",
6443N/A "displayName" : "New User",
6443N/A "meta" : {
6443N/A "created" : "2013-04-11T09:58:27Z"
6443N/A },
6443N/A "manager" : [ {
6443N/A "_id" : "kvaughan",
6443N/A "displayName" : "Kirsten Vaughan"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>To delete a resource only if the resource matches a particular version,
6443N/A use an <literal>If-Match: <replaceable>revision</replaceable></literal>
6443N/A header.</para>
6443N/A
7097N/A <screen>$ <userinput>curl
6443N/A --user kvaughan:bribery
7097N/A http://opendj.example.com:8080/users/newuser?_fields=_rev</userinput>
7097N/A<computeroutput>{"_rev":"000000006d8d7358"}</computeroutput>
7097N/A
7097N/A$ <userinput>curl \
7097N/A --request DELETE \
7097N/A --user kvaughan:bribery \
7097N/A --header "If-Match: 000000006d8d7358" \
7158N/A http://opendj.example.com:8080/users/newuser</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "00000000383f3cae",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1212",
6443N/A "emailAddress" : "newuser@example.com"
6443N/A },
6443N/A "_id" : "newuser",
6443N/A "name" : {
6443N/A "familyName" : "New",
6443N/A "givenName" : "User"
6443N/A },
6443N/A "userName" : "newuser@example.com",
6443N/A "displayName" : "New User",
6443N/A "meta" : {
6443N/A "created" : "2013-04-11T12:48:48Z"
6443N/A },
6443N/A "manager" : [ {
6443N/A "_id" : "kvaughan",
6443N/A "displayName" : "Kirsten Vaughan"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <orderedlist>
6443N/A <para>To delete a resource and all its children, you must change the
6443N/A configuration, get the REST LDAP gateway or HTTP Connection Handler to
6443N/A reload its configuration, and perform the operation as a user who has the
6443N/A access rights required. The following steps show one way to do this with
6443N/A the HTTP Connection Handler.</para>
6443N/A
6443N/A <para>In this case the LDAP view of the user to delete shows two child
6443N/A entries.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>ldapsearch --port 1389 --baseDN uid=nbohr,ou=people,dc=example,dc=com "(&amp;)" dn</userinput>
7097N/A<computeroutput>dn: uid=nbohr,ou=People,dc=example,dc=com
6443N/A
6443N/Adn: cn=quantum dot,uid=nbohr,ou=People,dc=example,dc=com
6443N/A
7097N/Adn: cn=qubit generator,uid=nbohr,ou=People,dc=example,dc=com</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <listitem>
6443N/A <para>In the configuration file for the HTTP Connection Handler, by default
6443N/A <filename>/path/to/opendj/config/http-config.json</filename>, set
6443N/A <literal>"useSubtreeDelete" : true</literal>.</para>
6443N/A
6443N/A <note>
6443N/A <para>After this change, only users who have access to request a tree
6443N/A delete can delete resources.</para>
6443N/A </note>
6443N/A </listitem>
6443N/A
6443N/A <listitem>
6443N/A <para>Force the HTTP Connection Handler to reread its configuration.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>dsconfig \
7097N/A set-connection-handler-prop \
7097N/A --hostname opendj.example.com \
7097N/A --port 4444 \
7097N/A --bindDN "cn=Directory Manager" \
7097N/A --bindPassword password \
7097N/A --handler-name "HTTP Connection Handler" \
7097N/A --set enabled:false \
7097N/A --no-prompt</userinput>
7097N/A
7097N/A$ <userinput>dsconfig \
7097N/A set-connection-handler-prop \
7097N/A --hostname opendj.example.com \
7097N/A --port 4444 \
7097N/A --bindDN "cn=Directory Manager" \
7097N/A --bindPassword password \
7097N/A --handler-name "HTTP Connection Handler" \
7097N/A --set enabled:true \
7097N/A --no-prompt</userinput>
7097N/A </screen>
6443N/A </listitem>
6443N/A
6443N/A <listitem>
6443N/A <para>Delete as a user who has rights to perform a subtree delete on
6443N/A the resource.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --request DELETE \
7097N/A --user kvaughan:bribery \
7158N/A http://opendj.example.com:8080/users/nbohr</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "000000003d912113",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1212",
6443N/A "emailAddress" : "nbohr@example.com"
6443N/A },
6443N/A "_id" : "nbohr",
6443N/A "name" : {
6443N/A "familyName" : "Bohr",
6443N/A "givenName" : "Niels"
6443N/A },
6443N/A "userName" : "nbohr@example.com",
6443N/A "displayName" : "Niels Bohr"
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </orderedlist>
6443N/A </section>
6443N/A
6443N/A <section xml:id="patch-rest">
6443N/A <title>Patching Resources</title>
6443N/A
6443N/A <para>OpenDJ lets you patch JSON resources, updating part of the resource
6443N/A rather than replacing it. For example, you could change Babs Jensen's
6443N/A email address by issuing an HTTP PATCH request, as in the example that
6443N/A follows.</para>
6443N/A
6443N/A <para>Notice that the data sent specifies the type of patch operation, the
6443N/A field to change, and a value that depends on the field you change and on the
6443N/A operation. A single-valued field takes an object, boolean, string, or number
6443N/A depending on its type, whereas a multi-valued field takes an array of values.
6443N/A Getting the type wrong results in an error. Also notice that the patch data is
6443N/A itself an array, since you could patch more than one part of the resource by
6443N/A using a set of patch operations in the same request.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A --request PATCH \
7097N/A --header "Content-Type: application/json" \
7142N/A --data '[
7142N/A {
7142N/A "operation": "replace",
7142N/A "field": "/contactInformation/emailAddress",
7142N/A "value": "babs@example.com"
7142N/A }
7097N/A ]' \
7158N/A http://opendj.example.com:8080/users/bjensen</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "00000000f3fdd370",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1862",
6443N/A "emailAddress" : "babs@example.com"
6443N/A },
6443N/A "_id" : "bjensen",
6443N/A "name" : {
6443N/A "familyName" : "Jensen",
6443N/A "givenName" : "Barbara"
6443N/A },
6443N/A "userName" : "babs@example.com",
6443N/A "displayName" : "Barbara Jensen",
6443N/A "meta" : {
6443N/A "lastModified" : "2013-05-13T14:35:31Z"
6443N/A },
6443N/A "manager" : [ {
6443N/A "_id" : "trigden",
6443N/A "displayName" : "Torrey Rigden"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <variablelist>
6443N/A <para>OpenDJ supports four types of patch operation.</para>
6443N/A
6443N/A <varlistentry>
6443N/A <term>"add"</term>
6443N/A <listitem>
6443N/A <para>The add operation ensures that the target field contains the value
6443N/A provided, creating parent fields as necessary.</para>
6443N/A
7321N/A <para>
7321N/A If the target field is single-valued and a value already exists,
7321N/A then that value is replaced with the value you provide.
7321N/A <emphasis>Note that you do not get an error when adding a value
7321N/A to a single-valued field that already has a value.</emphasis>
7321N/A A single-valued field is one whose value is not an array
7321N/A (an object, string, boolean, or number).
7321N/A </para>
6443N/A
6443N/A <para>If the target field is multi-valued, then the array of values you
6443N/A provide is merged with the set of values already in the resource. New
6443N/A values are added, and duplicate values are ignored. A multi-valued field
6443N/A takes an array value.</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term>"remove"</term>
6443N/A <listitem>
6443N/A <para>The remove operation ensures that the target field does not contain
6443N/A the value provided. If you do not provide a value, the entire field is
6443N/A removed if it already exists.</para>
6443N/A
6443N/A <para>If the target field is single-valued and a value is provided, then
6443N/A the provided value must match the existing value to remove, otherwise the
6443N/A field is left unchanged.</para>
6443N/A
6443N/A <para>If the target field is multi-valued, then values in the array you
6443N/A provide are removed from the existing set of values.</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term>"replace"</term>
6443N/A <listitem>
6443N/A <para>The replace operation removes existing values on the target field,
6443N/A and replaces them with the values you provide. It is equivalent to
6443N/A performing a remove on the field, then an add with the values you
6443N/A provide.</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term>"increment"</term>
6443N/A <listitem>
6443N/A <para>The increment operation increments or decrements the value or values
6443N/A in the target field by the amount you specify, which is positive to
6443N/A increment, negative to decrement. The target field must be a number or
6443N/A a set of numbers. The value you provide must be a single number.</para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A </variablelist>
6443N/A
6443N/A <para>One key nuance in how patch works with OpenDJ has to do with
6443N/A multi-valued fields. Although JSON resources represent multi-valued fields as
6443N/A <emphasis>arrays</emphasis>, OpenDJ treats those values as
6443N/A <emphasis>sets</emphasis>. In other words, values in the field are unique,
6443N/A and the ordering of an array of values is not meaningful in the context of
6443N/A patch operations. If you reference array values by index, OpenDJ returns
6443N/A an error.<footnote><para>OpenDJ does let you use a hyphen as the last element
6443N/A of the "field" JSON pointer value to add an element to the set, as in
6443N/A <command>curl --user kvaughan:bribery --request PATCH --header "Content-Type:
6443N/A application/json" --data '[{ "operation" : "add", "field" : "/members/-",
6443N/A "value" : { "_id" : "bjensen" } }]'
6443N/A http://opendj.example.com:8080/groups/Directory%20Administrators</command>.</para>
6443N/A </footnote></para>
6443N/A
6443N/A <para>Instead use the patch operations as if arrays values were sets. For
6443N/A example, you can include Barbara Jensen in a group by adding her to the set
6443N/A of members.</para>
6443N/A
7158N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A --request PATCH \
7097N/A --header "Content-Type: application/json" \
7142N/A --data '[
7142N/A {
7142N/A "operation": "add",
7142N/A "field": "/members",
7142N/A "value": [
7142N/A {
7142N/A "_id": "bjensen"
7142N/A }
7142N/A ]
7142N/A }
7097N/A ]' \
7158N/A http://opendj.example.com:8080/groups/Directory%20Administrators</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "00000000b70c881a",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "_id" : "Directory Administrators",
6443N/A "displayName" : "Directory Administrators",
6443N/A "meta" : {
6443N/A "lastModified" : "2013-05-13T16:40:23Z"
6443N/A },
6443N/A "members" : [ {
6443N/A "_id" : "kvaughan",
6443N/A "displayName" : "Kirsten Vaughan"
6443N/A }, {
6443N/A "_id" : "rdaugherty",
6443N/A "displayName" : "Robert Daugherty"
6443N/A }, {
6443N/A "_id" : "bjensen",
6443N/A "displayName" : "Barbara Jensen"
6443N/A }, {
6443N/A "_id" : "hmiller",
6443N/A "displayName" : "Harry Miller"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>Removing her from the group is similar.</para>
6443N/A
7158N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A --request PATCH \
7097N/A --header "Content-Type: application/json" \
7142N/A --data '[
7142N/A {
7142N/A "operation": "remove",
7142N/A "field": "/members",
7142N/A "value": [
7142N/A {
7142N/A "_id": "bjensen"
7142N/A }
7142N/A ]
7142N/A }
7097N/A ]' \
7158N/A http://opendj.example.com:8080/groups/Directory%20Administrators</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "00000000e241797e",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "_id" : "Directory Administrators",
6443N/A "displayName" : "Directory Administrators",
6443N/A "meta" : {
6443N/A "lastModified" : "2013-05-13T16:40:55Z"
6443N/A },
6443N/A "members" : [ {
6443N/A "_id" : "kvaughan",
6443N/A "displayName" : "Kirsten Vaughan"
6443N/A }, {
6443N/A "_id" : "rdaugherty",
6443N/A "displayName" : "Robert Daugherty"
6443N/A }, {
6443N/A "_id" : "hmiller",
6443N/A "displayName" : "Harry Miller"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>You can use resource revision numbers in <literal>If-Match:
6443N/A <replaceable>revision</replaceable></literal> headers to patch the resource
6443N/A only if the resource matches a particular version.</para>
6443N/A
7097N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7158N/A http://opendj.example.com:8080/users/bjensen?_fields=_rev</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "00000000c1b6d4c7"
7097N/A}</computeroutput>
7097N/A
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A --request PATCH \
7097N/A --header "If-Match: 00000000c1b6d4c7" \
7097N/A --header "Content-Type: application/json" \
7142N/A --data '[
7142N/A {
7142N/A "operation": "add",
7142N/A "field": "/contactInformation/emailAddress",
7142N/A "value": "babs@example.com"
7142N/A }
7097N/A ]' \
7158N/A http://opendj.example.com:8080/users/bjensen</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "00000000f946d377",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1862",
6443N/A "emailAddress" : "babs@example.com"
6443N/A },
6443N/A "_id" : "bjensen",
6443N/A "name" : {
6443N/A "familyName" : "Jensen",
6443N/A "givenName" : "Barbara"
6443N/A },
6443N/A "userName" : "babs@example.com",
6443N/A "displayName" : "Barbara Jensen",
6443N/A "meta" : {
6443N/A "lastModified" : "2013-05-13T16:56:33Z"
6443N/A },
6443N/A "manager" : [ {
6443N/A "_id" : "trigden",
6443N/A "displayName" : "Torrey Rigden"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A
6443N/A <para>The resource revision changes after you successfully perform the patch
6443N/A operation.</para>
6443N/A </section>
6443N/A
6443N/A <section xml:id="action-rest">
6443N/A <title>Using Actions</title>
6443N/A
6443N/A <para>OpenDJ implements an action that lets the server set the resource ID
6443N/A on creation. To use this action, perform an HTTP POST with header
6443N/A <literal>Content-Type: application/json</literal>,
6443N/A <literal>_action=create</literal> in the query string, and the JSON content of
6443N/A your resource.</para>
6443N/A
6443N/A <para>The following example creates a new user entry.</para>
6443N/A
7158N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --request POST \
7097N/A --user kvaughan:bribery \
7097N/A --header "Content-Type: application/json" \
7142N/A --data '{
7142N/A "_id": "newuser",
7142N/A "contactInformation": {
7142N/A "telephoneNumber": "+1 408 555 1212",
7142N/A "emailAddress": "newuser@example.com"
7142N/A },
7142N/A "name": {
7142N/A "familyName": "New",
7142N/A "givenName": "User"
7142N/A },
7142N/A "displayName": "New User",
7142N/A "manager": [
7142N/A {
7142N/A "_id": "kvaughan",
7142N/A "displayName": "Kirsten Vaughan"
7142N/A }
7142N/A ]
7097N/A }' \
7158N/A http://opendj.example.com:8080/users?_action=create</userinput>
7097N/A<computeroutput>{
6443N/A "_rev" : "0000000034a23ca7",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1212",
6443N/A "emailAddress" : "newuser@example.com"
6443N/A },
6443N/A "_id" : "newuser",
6443N/A "name" : {
6443N/A "familyName" : "New",
6443N/A "givenName" : "User"
6443N/A },
6443N/A "userName" : "newuser@example.com",
6443N/A "displayName" : "New User",
6443N/A "meta" : {
6443N/A "created" : "2013-04-11T11:19:08Z"
6443N/A },
6443N/A "manager" : [ {
6443N/A "_id" : "kvaughan",
6443N/A "displayName" : "Kirsten Vaughan"
6443N/A } ]
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </section>
6443N/A
6443N/A <section xml:id="query-rest">
6443N/A <title>Querying Resource Collections</title>
6443N/A
6443N/A <para>To query resource collections, perform an HTTP GET with a
7307N/A <literal>_queryFilter=<replaceable>expression</replaceable></literal> parameter
6443N/A in your query string.</para>
6443N/A
7307N/A <para>
7307N/A The following listing summarizes the string representation
7307N/A for the filter expression.
7307N/A Continue reading for additional explanation.
7307N/A </para>
7307N/A
7307N/A <programlisting language="none">
7307N/AExpr = OrExpr
7307N/AOrExpr = AndExpr ( 'or' AndExpr ) *
7307N/AAndExpr = NotExpr ( 'and' NotExpr ) *
7307N/ANotExpr = '!' PrimaryExpr | PrimaryExpr
7307N/APrimaryExpr = '(' Expr ')' | ComparisonExpr | PresenceExpr | LiteralExpr
7307N/AComparisonExpr = Pointer OpName JsonValue
7307N/APresenceExpr = Pointer 'pr'
7307N/ALiteralExpr = 'true' | 'false'
7307N/APointer = JSON pointer
7307N/AOpName = 'eq' | # equal to
7307N/A 'co' | # contains
7307N/A 'sw' | # starts with
7307N/A 'lt' | # less than
7307N/A 'le' | # less than or equal to
7307N/A 'gt' | # greater than
7307N/A 'ge' | # greater than or equal to
7307N/A STRING # extended operator
7307N/AJsonValue = NUMBER | BOOLEAN | '"' UTF8STRING '"'
7307N/ASTRING = ASCII string not containing white-space
7307N/AUTF8STRING = UTF-8 string possibly containing white-space
7307N/A </programlisting>
7307N/A
7307N/A <para>
7307N/A The following table shows some LDAP search filters
7307N/A with corresponding query filter expressions.
7307N/A </para>
7307N/A
7307N/A <table pgwide="1">
7307N/A <title>LDAP Search and REST Query Filters</title>
7307N/A
7307N/A <tgroup cols="2">
7307N/A
7307N/A <colspec colnum="1" colwidth="1*" />
7307N/A <colspec colnum="2" colwidth="1*" />
7307N/A
7307N/A <thead>
7307N/A <row>
7307N/A <entry>
7307N/A LDAP Filter
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A REST Filter
7307N/A </entry>
7307N/A </row>
7307N/A </thead>
7307N/A
7307N/A <tbody>
7307N/A <row>
7307N/A <entry>
7307N/A (&amp;)
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=true
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (uid=*)
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=_id+pr
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (uid=bjensen)
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=_id+eq+"bjensen"
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (uid=*jensen*)
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=_id+co+"jensen"
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (uid=jensen*)
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=_id+sw+"jensen"
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (&amp;(uid=*jensen*)(cn=babs*))
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=(_id+co+"jensen"+and+displayName+sw+"babs")
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (|(uid=*jensen*)(cn=sam*))
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=(_id+co+"jensen"+or+displayName+sw+"sam")
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (!(uid=*jensen*))
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=!(_id+co+"jensen")
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (uid&lt;=jensen)
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=_id+le+"jensen"
7307N/A </entry>
7307N/A </row>
7307N/A
7307N/A <row>
7307N/A <entry>
7307N/A (uid>=jensen)
7307N/A </entry>
7307N/A
7307N/A <entry>
7307N/A _queryFilter=_id+ge+"jensen"
7307N/A </entry>
7307N/A </row>
7307N/A </tbody>
7307N/A </tgroup>
7307N/A </table>
7307N/A
6443N/A <variablelist>
7307N/A <para>For query operations, your filter <replaceable>expression</replaceable>
7307N/A is constructed from the following building blocks.
6443N/A Make sure you URL encode the filter expressions, which are shown here
6443N/A without URL encoding to make them easier to read.</para>
6443N/A
6443N/A <para>In these expressions the simplest
6443N/A <replaceable>json-pointer</replaceable> is a field of the JSON resource,
6443N/A such as <literal>userName</literal> or <literal>id</literal>. A
6443N/A <replaceable>json-pointer</replaceable> can however point to nested
6443N/A elements as described in the <link xlink:show="new"
6443N/A xlink:href="http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer">JSON
6443N/A Pointer</link> Internet-Draft.</para>
6443N/A
6443N/A <varlistentry>
6443N/A <term>Comparison expressions</term>
6443N/A <listitem>
6443N/A <para>You can build filters using the following comparison expressions.</para>
6443N/A
6443N/A <variablelist>
6443N/A <varlistentry>
6443N/A <term><literal><replaceable>json-pointer</replaceable> eq <replaceable>json-value</replaceable></literal></term>
6443N/A <listitem>
6443N/A <para>Matches when the pointer equals the value, as in the following
6443N/A example.</para>
6443N/A
7158N/A <screen width="87">
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=userName+eq+"bjensen@example.com"'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "_rev" : "00000000315fb731",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "manager" : [ {
6443N/A "_id" : "trigden",
6443N/A "displayName" : "Torrey Rigden"
6443N/A } ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 1862",
6443N/A "emailAddress" : "bjensen@example.com"
6443N/A },
6443N/A "_id" : "bjensen",
6443N/A "name" : {
6443N/A "familyName" : "Jensen",
6443N/A "givenName" : "Barbara"
6443N/A },
6443N/A "userName" : "bjensen@example.com",
6443N/A "displayName" : "Barbara Jensen"
6443N/A } ],
6443N/A "resultCount" : 1,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><literal><replaceable>json-pointer</replaceable> co <replaceable>json-value</replaceable></literal></term>
6443N/A <listitem>
6443N/A <para>Matches when the pointer contains the value, as in the following
6443N/A example.</para>
6443N/A
7158N/A <screen width="91">
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=userName+co+"jensen"&amp;_fields=userName'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "userName" : "ajensen@example.com"
6443N/A }, {
6443N/A "userName" : "bjensen@example.com"
6443N/A }, {
6443N/A "userName" : "gjensen@example.com"
6443N/A }, {
6443N/A "userName" : "jjensen@example.com"
6443N/A }, {
6443N/A "userName" : "kjensen@example.com"
6443N/A }, {
6443N/A "userName" : "rjensen@example.com"
6443N/A }, {
6443N/A "userName" : "tjensen@example.com"
6443N/A } ],
6443N/A "resultCount" : 7,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><literal><replaceable>json-pointer</replaceable> sw <replaceable>json-value</replaceable></literal></term>
6443N/A <listitem>
6443N/A <para>Matches when the pointer starts with the value, as in the
6443N/A following example.</para>
6443N/A
7158N/A <screen width="87">
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=userName+sw+"ab"&amp;_fields=userName'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "userName" : "abarnes@example.com"
6443N/A }, {
6443N/A "userName" : "abergin@example.com"
6443N/A } ],
6443N/A "resultCount" : 2,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><literal><replaceable>json-pointer</replaceable> lt <replaceable>json-value</replaceable></literal></term>
6443N/A <listitem>
6443N/A <para>Matches when the pointer is less than the value, as in the
6443N/A following example.</para>
6443N/A
7158N/A <screen width="87">
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=userName+lt+"ac"&amp;_fields=userName'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "userName" : "abarnes@example.com"
6443N/A }, {
6443N/A "userName" : "abergin@example.com"
6443N/A } ],
6443N/A "resultCount" : 2,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><literal><replaceable>json-pointer</replaceable> le <replaceable>json-value</replaceable></literal></term>
6443N/A <listitem>
6443N/A <para>Matches when the pointer is less than or equal to the value, as
6443N/A in the following example.</para>
6443N/A
7158N/A <screen width="87">
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=userName+le+"ad"&amp;_fields=userName'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "userName" : "abarnes@example.com"
6443N/A }, {
6443N/A "userName" : "abergin@example.com"
6443N/A }, {
6443N/A "userName" : "achassin@example.com"
6443N/A } ],
6443N/A "resultCount" : 3,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><literal><replaceable>json-pointer</replaceable> gt <replaceable>json-value</replaceable></literal></term>
6443N/A <listitem>
6443N/A <para>Matches when the pointer is greater than the value, as in the
6443N/A following example.</para>
6443N/A
7158N/A <screen width="87">
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=userName+gt+"tt"&amp;_fields=userName'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "userName" : "ttully@example.com"
6443N/A }, {
6443N/A "userName" : "tward@example.com"
6443N/A }, {
6443N/A "userName" : "wlutz@example.com"
6443N/A } ],
6443N/A "resultCount" : 3,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term><literal><replaceable>json-pointer</replaceable> ge <replaceable>json-value</replaceable></literal></term>
6443N/A <listitem>
6443N/A <para>Matches when the pointer is greater than or equal to the value,
6443N/A as in the following example.</para>
6443N/A
7158N/A <screen width="87">
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=userName+ge+"tw"&amp;_fields=userName'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "userName" : "tward@example.com"
6443N/A }, {
6443N/A "userName" : "wlutz@example.com"
6443N/A } ],
6443N/A "resultCount" : 2,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A </variablelist>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term>Presence expression</term>
6443N/A <listitem>
6443N/A <para><literal><replaceable>json-pointer</replaceable> pr</literal> matches
6443N/A any resource on which the <replaceable>json-pointer</replaceable> is
6443N/A present, as in the following example.</para>
6443N/A
7158N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=userName%20pr'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "_rev" : "000000002210a544",
6443N/A "schemas" : [ "urn:scim:schemas:core:1.0" ],
6443N/A "manager" : [ {
6443N/A "_id" : "scarter",
6443N/A "displayName" : "Sam Carter"
6443N/A } ],
6443N/A "contactInformation" : {
6443N/A "telephoneNumber" : "+1 408 555 9445",
6443N/A "emailAddress" : "abarnes@example.com"
6443N/A },
6443N/A "_id" : "abarnes",
6443N/A "name" : {
6443N/A "familyName" : "Barnes",
6443N/A "givenName" : "Anne-Louise"
6443N/A },
6443N/A "userName" : "abarnes@example.com",
6443N/A "displayName" : "Anne-Louise Barnes"
6443N/A },&#8230; many entries omitted &#8230;
6443N/A "_id" : "newuser",
6443N/A "name" : {
6443N/A "familyName" : "New",
6443N/A "givenName" : "User"
6443N/A },
6443N/A "userName" : "newuser@example.com",
6443N/A "displayName" : "New User",
6443N/A "meta" : {
6443N/A "created" : "2013-03-26T10:52:42Z"
6443N/A }
6443N/A } ],
6443N/A "resultCount" : 152,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term>Literal expressions</term>
6443N/A <listitem>
6443N/A <para><literal>true</literal> matches any resource in the collection.</para>
6443N/A <para><literal>false</literal> matches no resource in the collection.</para>
6443N/A
6443N/A <para>In other words you can list all resources in a collection as in the
6443N/A following example.</para>
6443N/A
7158N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/groups?_queryFilter=true&amp;_fields=displayName'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "displayName" : "Accounting Managers"
6443N/A }, {
6443N/A "displayName" : "Directory Administrators"
6443N/A }, {
6443N/A "displayName" : "HR Managers"
6443N/A }, {
6443N/A "displayName" : "PD Managers"
6443N/A }, {
6443N/A "displayName" : "QA Managers"
6443N/A } ],
6443N/A "resultCount" : 5,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6443N/A <term>Complex expressions</term>
6443N/A <listitem>
6443N/A <para>You can combine expressions using boolean operators
6443N/A <literal>and</literal>, <literal>or</literal>, and <literal>!</literal>
6443N/A (not), using parentheses,
6443N/A <literal>(<replaceable>expression</replaceable>)</literal>, to group
6443N/A expressions. The following example queries resources with last name
6443N/A Jensen and manager name starting with <literal>Bar</literal>. Notice that
6443N/A the filters use the JSON pointers <literal>name/familyName</literal> and
6443N/A <literal>manager/displayName</literal> to identify the fields that are
6443N/A nested inside the <literal>name</literal> and <literal>manager</literal>
6443N/A objects.</para>
6443N/A
7158N/A <screen>
7097N/A$ <userinput>curl \
7097N/A --user kvaughan:bribery \
7097N/A 'http://opendj.example.com:8080/users?_queryFilter=\
7097N/A(userName+co+"jensen"+and+manager/displayName+sw+"Sam")&amp;_fields=displayName'</userinput>
7097N/A<computeroutput>{
6443N/A "result" : [ {
6443N/A "displayName" : "Jody Jensen"
6443N/A }, {
6443N/A "displayName" : "Ted Jensen"
6443N/A } ],
6443N/A "resultCount" : 2,
6443N/A "pagedResultsCookie" : null,
6443N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A </variablelist>
6443N/A
6443N/A <!-- Pending implementation https://bugster.forgerock.org/jira/browse/OPENDJ-702
6443N/A <para>You can have the server sort JSON resources before it returns them by
6443N/A using the <literal>_sortKeys[+-]=<replaceable>field</replaceable>[,&#8230;]</literal>
6443N/A query string.</para>
6443N/A -->
6443N/A
6443N/A <variablelist>
7086N/A <para>
7086N/A You can page through search results using the following query string parameters.
7086N/A </para>
6443N/A
6443N/A <varlistentry>
6872N/A <term><literal>_pagedResultsCookie=<replaceable>string</replaceable></literal></term>
6443N/A <listitem>
6872N/A <para>
6872N/A Opaque cookie used by the server to keep track of the position
6872N/A in the search results.
7086N/A </para>
6872N/A
7086N/A <para>
7086N/A In the request also set <literal>_pageSize</literal> greater than zero.
7086N/A </para>
6872N/A
7086N/A <para>
6872N/A You receive the cookie value from the server on the first request,
6872N/A and then supply the cookie value in subsequent requests
6872N/A until the server returns a <literal>null</literal> cookie,
6872N/A meaning that the final page of results has been returned.
6872N/A </para>
6872N/A </listitem>
6872N/A </varlistentry>
6872N/A
6872N/A <varlistentry>
6872N/A <term><literal>_pagedResultsOffset=<replaceable>integer</replaceable></literal></term>
6872N/A <listitem>
6872N/A <para>
7086N/A When <literal>_pageSize</literal> is greater than zero,
7086N/A use this as an index in the result set indicating the page to return.
7086N/A </para>
7086N/A
7086N/A <para>
7086N/A When the value of <literal>_pagedResultsOffset</literal> is 1 or more,
7086N/A the server returns the page starting from the specified index.
7086N/A </para>
7086N/A
7086N/A <para>
7086N/A When <literal>_pagedResultsCookie</literal> is also set,
7086N/A the starting point is the position tracked by the cookie.
7086N/A Otherwise the offset is relative to the beginning of the result set.
7086N/A </para>
6872N/A
7086N/A <para>
7086N/A For example, <literal>_pageSize=2&amp;_pagedResultsOffset=1</literal>
7086N/A returns the third and fourth entries of the results.
7086N/A <literal>_pageSize=3&amp;_pagedResultsOffset=2&amp;_pagedResultsCookie=<replaceable>cookie</replaceable></literal>
7086N/A returns the seventh, eighth, and ninth entries
7086N/A counting from the position tracked by the cookie.
7086N/A </para>
6872N/A
7086N/A <para>
7086N/A When <literal>_pageSize</literal> is not set,
7086N/A or when the value of <literal>_pagedResultsOffset</literal> is 0 or less,
7086N/A the setting has no effect.
7086N/A </para>
7086N/A
7086N/A <para>
7086N/A If other <literal>_pageSize</literal> is set,
7086N/A but the offset points to a page beyond the last of the search results,
7086N/A the result set returned is empty.
6872N/A </para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A
6443N/A <varlistentry>
6872N/A <term><literal>_pageSize=<replaceable>integer</replaceable></literal></term>
6443N/A <listitem>
6872N/A <para>
7086N/A Return query results in pages of this size,
7086N/A where <replaceable>integer</replaceable> should be greater than zero.
7086N/A </para>
6872N/A
7086N/A <para>
7086N/A Page sizes of zero or less have no effect,
7086N/A with the outcome that all results are returned,
7086N/A and <literal>_pagedResultsCookie</literal> is <literal>null</literal>
7086N/A in the response.
7086N/A </para>
7086N/A
7086N/A <para>
6872N/A After the initial request, use <literal>_pagedResultsCookie</literal>
6872N/A to page through the results.
6872N/A </para>
6872N/A
6872N/A
6872N/A <para>
6872N/A The following example demonstrates the use of paged results.
6872N/A
6872N/A The first call requests 5 results per page, and retrieves the first page.
6872N/A
6872N/A The next call provides the cookie to request the next 5 results.
6872N/A
6872N/A The final call provides the cookie and requests the 10th page of results
7086N/A after the last page of results specified by the cookie.
6872N/A </para>
6872N/A
7158N/A <screen width="87">
7097N/A$ <userinput>curl \
7097N/A --user bjensen:hifalutin \
7097N/A "http://opendj.example.com:8080/users?_queryFilter=true&amp;_fields=userName&amp;_pageSize=5"</userinput>
7097N/A<computeroutput>{
6872N/A "result" : [ {
6872N/A "userName" : "abarnes@example.com"
6872N/A }, {
6872N/A "userName" : "abergin@example.com"
6872N/A }, {
6872N/A "userName" : "achassin@example.com"
6872N/A }, {
6872N/A "userName" : "ahall@example.com"
6872N/A }, {
6872N/A "userName" : "ahel@example.com"
6872N/A } ],
6872N/A "resultCount" : 5,
6872N/A "pagedResultsCookie" : "AAAAAAAAAA8=",
6872N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
6443N/A
7097N/A$ <userinput>curl \
7097N/A --user bjensen:hifalutin \
7097N/A "http://opendj.example.com:8080/users?_queryFilter=true&amp;_fields=userName&amp;_pageSize=5\
7097N/A&amp;_pagedResultsCookie=AAAAAAAAAA8="</userinput>
7097N/A<computeroutput>{
6872N/A "result" : [ {
6872N/A "userName" : "ahunter@example.com"
6872N/A }, {
6872N/A "userName" : "ajensen@example.com"
6872N/A }, {
6872N/A "userName" : "aknutson@example.com"
6872N/A }, {
6872N/A "userName" : "alangdon@example.com"
6872N/A }, {
6872N/A "userName" : "alutz@example.com"
6872N/A } ],
6872N/A "resultCount" : 5,
6872N/A "pagedResultsCookie" : "AAAAAAAAABQ=",
6872N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
6872N/A
7097N/A$ <userinput>curl \
7097N/A --user bjensen:hifalutin \
7097N/A "http://opendj.example.com:8080/users?_queryFilter=true&amp;_fields=userName&amp;_pageSize=5\
7097N/A&amp;_pagedResultsCookie=AAAAAAAAAA8=&amp;_pagedResultsOffset=10"</userinput>
7097N/A<computeroutput>{
6872N/A "result" : [ {
6872N/A "userName" : "gtriplet@example.com"
6872N/A }, {
6872N/A "userName" : "gtyler@example.com"
6872N/A }, {
6872N/A "userName" : "hmiller@example.com"
6872N/A }, {
6872N/A "userName" : "jbourke@example.com"
6872N/A }, {
6872N/A "userName" : "jbrown@example.com"
6872N/A } ],
6872N/A "resultCount" : 5,
6872N/A "pagedResultsCookie" : "AAAAAAAAAEY=",
6872N/A "remainingPagedResults" : -1
7097N/A}</computeroutput>
7097N/A </screen>
6872N/A
6872N/A <para>
6872N/A Notice that <literal>"remainingPagedResults" : -1</literal> in each case
6872N/A meaning that the number of remaining results is not known.
6872N/A </para>
6443N/A </listitem>
6443N/A </varlistentry>
6443N/A </variablelist>
6443N/A </section>
6443N/A</chapter>