chap-data.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
!
-->
<chapter xml:id='chap-data'
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>Accessing Data Objects</title>
<indexterm>
<primary>Data</primary>
<secondary>accessing</secondary>
</indexterm>
<para>
OpenIDM supports a variety of objects that can be addressed via a URL or URI.
You can access data objects by using scripts (through the Resource API) or by
using direct HTTP calls (through the REST API).
</para>
<para>
The following sections describe these two methods of accessing data objects,
and provide information on constructing and calling data queries.
</para>
<section xml:id="data-scripts">
<title>Accessing Data Objects by Using Scripts</title>
<indexterm>
<primary>Objects</primary>
<secondary>Script access</secondary>
</indexterm>
<para>
OpenIDM's uniform programming model means that all objects are queried and
manipulated in the same way, using the Resource API. The URL or URI that is
used to identify the target object for an operation depends on the object
type. For an explanation of object types, see the
<link xlink:href="integrators-guide#appendix-objects"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Data Models and
Objects Reference</citetitle></link>. For more information about scripts and
the objects available to scripts, see the
<link xlink:href="integrators-guide#appendix-scripting"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Scripting
Reference</citetitle></link>.
</para>
<para>
You can use the Resource API to obtain managed objects, configuration
objects, and repository objects, as follows:
</para>
<programlisting language="javascript">
val = openidm.read("managed/organization/mysampleorg")
val = openidm.read("config/custom/mylookuptable")
val = openidm.read("repo/custom/mylookuptable")
</programlisting>
<para>
For information about constructing an object ID, see <link
xlink:href="integrators-guide#rest-uri-scheme"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>URI Scheme</citetitle></link>
in the <citetitle>REST API Reference</citetitle>.
</para>
<para>
You can update entire objects with the <literal>update()</literal> function,
as follows.
</para>
<programlisting language="javascript">
openidm.update("managed/organization/mysampleorg", mymap)
openidm.update("config/custom/mylookuptable", mymap)
openidm.update("repo/custom/mylookuptable", mymap)
</programlisting>
<para>
For managed objects, you can partially update an object with the
<literal>patch()</literal> function.
</para>
<programlisting language="javascript">
openidm.patch("managed/organization/mysampleorg", rev, value)
</programlisting>
<para>
The <literal>create()</literal>, <literal>delete()</literal>, and
<literal>query()</literal> functions work the same way.
</para>
</section>
<section xml:id="data-rest">
<title>Accessing Data Objects by Using the REST API</title>
<para>
OpenIDM provides RESTful access to data objects via a REST API. To access
objects over REST, you can use a browser-based REST client, such as the
<link xlink:href="https://chrome.google.com/webstore/detail/simple-rest-client/fhjcajmcbmldlhcimfajhfbgofnpcjmb">
Simple REST Client</link> for Chrome, or <link
xlink:href="https://addons.mozilla.org/en-US/firefox/addon/restclient/">
RESTClient</link> for Firefox. Alternatively you can use the <link
xlink:show="new" xlink:href="http://curl.haxx.se/"><command>curl</command>
</link> command-line utility.
</para>
<para>
For a comprehensive overview of the REST API, see the <link
xlink:href="integrators-guide#appendix-rest"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>REST API
Reference</citetitle></link> appendix.
</para>
<para>
To obtain a managed object through the REST API, depending on your security
settings and authentication configuration, perform an HTTP GET on the
corresponding URL, for example
<literal>https://localhost:8443/openidm/managed/organization/mysampleorg</literal>.
</para>
<para>
By default, the HTTP GET returns a JSON representation of the object.
</para>
</section>
<section xml:id="queries">
<title>Defining and Calling Queries</title>
<para>
OpenIDM supports an advanced query model that enables you to define queries,
and to call them over the REST or Resource API. Three types of queries are
supported, on both managed, and system objects:
</para>
<itemizedlist>
<listitem>
<para>
Common filter expressions
</para>
</listitem>
<listitem>
<para>
Parameterized, or predefined queries
</para>
</listitem>
<listitem>
<para>
Native query expressions
</para>
</listitem>
</itemizedlist>
<para>
Each of these mechanisms is discussed in the following sections.
</para>
<section xml:id="query-filters">
<title>Common Filter Expressions</title>
<para>
The ForgeRock REST API defines common filter expressions, that enable you to
form arbitrary queries using a number of supported filter operations. This
query capability is the standard way to query data if no predefined query
exists, and is supported for all managed and system objects.
</para>
<para>
Common filter expressions are useful in that they do not require knowledge
of how the object is stored and do not require additions to the repository
configuration.
</para>
<para>
Common filter expressions are called with the
<literal>_queryFilter</literal> keyword. The following example uses a common
filter expression to retrieve managed user objects whose user name is Smith.
</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
"https://localhost:8443/openidm/managed/user?_queryFilter=userName%20eq%20%22smith%22"</screen>
<para>
The filter is URL encoded in this example. The corresponding filter using
the resource API would be:
</para>
<screen>openidm.query("managed/user", { "_queryFilter" : '/userName eq "smith"' });</screen>
<para>
Note that, this JavaScript invocation is internal and is not subject to the
same URL-encoding requirements that a GET request would be. Also, because
JavaScript supports the use of single quotes, it is not necessary to escape
the double quotes in this example.
</para>
<para>
For a list of supported filter operations, see
<xref linkend="constructing-queries" />.
</para>
<para>
Note that using common filter expressions to retrieve values from arrays is
currently not supported. If you need to search within an array you should
set up a predefined (parameterized) in your repository configuration. For
more information, see <xref linkend="parameterized-queries" />.
</para>
</section>
<section xml:id="parameterized-queries">
<title>Parameterized Queries</title>
<para>
Managed objects in the supported OpenIDM repositories can be accessed using
a parameterized query mechanism. Parameterized queries on repositories are
defined in the repository configuration (<filename>repo.*.json</filename>)
and are called by their <literal>_queryId</literal>.
</para>
<para>
Parameterized queries provide precise control over the query that is
executed. Such control might be useful for tuning, or for performing
database operations such as aggregation (which is not possible with a
common filter expression.)
</para>
<para>
Parameterized queries provide security and portability for the query call
signature, regardless of the back-end implementation. Queries that are
exposed over the REST interface <emphasis>must</emphasis> be parameterized
queries to guard against injection attacks and other misuse. Queries on the
officially supported repositories have been reviewed and hardened against
injection attacks.
</para>
<para>
For system objects, support for parameterized queries is restricted to
<literal>_queryId=query-all-ids</literal>. There is currently no support for
user-defined parameterized queries on system objects. Typically,
parameterized queries on system objects are not called directly over the
REST interface, but are issued from internal calls, such as correlation
queries.
</para>
<para>
A typical query definition is as follows:
</para>
<programlisting>
"query-all-ids" : "select _openidm_id from ${unquoted:_resource}"
</programlisting>
<para>
To call this query, you would reference its ID, as follows:
</para>
<programlisting>
?_queryId=query-all-ids
</programlisting>
<para>
The following example calls <literal>query-all-ids</literal> over the REST
interface:
</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids"</screen>
</section>
<section xml:id="native-queries">
<title>Native Query Expressions</title>
<para>
Native query expressions are supported for all managed objects and system
objects, and can be called directly, rather than being defined in the
repository configuration.
</para>
<para>
Native queries are intended specifically for internal callers, such as
custom scripts, and should be used only in situations where the common
filter or parameterized query facilities are insufficient. For example,
native queries are useful if the query needs to be generated dynamically.
</para>
<para>
The query expression is specific to the target resource. For repositories,
queries use the native language of the underlying data store. For system
objects that are backed by OpenICF connectors, queries use the applicable
query language of the system resource.
</para>
<para>
Native queries on the repository are made using the
<literal>_queryExpression</literal> keyword. For example:
</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
"https://localhost:8443/openidm/managed/user?_queryExpression=select+from+managed_user"
</screen>
<para>
Unless you have specifically enabled native queries over REST, the previous
command returns a 403 access denied error message. Native queries are not
portable and do not guard against injection attacks. Such query expressions
should therefore not be used or made accessible over the REST interface or
over HTTP, in production environments. They should be used only via the
internal Resource API. If you want to enable native queries over REST for
development, see the section on
<link xlink:href="integrators-guide#security-urls"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Protecting
Sensitive REST Interface URLs</citetitle></link>.
</para>
<para>
Alternatively, if you really need to expose native queries over HTTP, in a
selective manner, you can design a custom endpoint to wrap such access.
</para>
</section>
<section xml:id="constructing-queries">
<title>Constructing Queries</title>
<para>
The <literal>openidm.query</literal> function enables you to query OpenIDM
managed and system objects. The query syntax is
<literal>openidm.query(id, params)</literal>, where <literal>id</literal>
specifies the object on which the query should be performed and
<literal>params</literal> provides the parameters that are passed to the
query, either <literal>_queryFilter</literal> or
<literal>_queryID</literal>. For example:
</para>
<programlisting language="javascript">
var params = {
'_queryFilter' : 'givenName co "' + sourceCriteria + '" or ' + 'sn co "'
+ sourceCriteria + '"'
};
var results = openidm.query("system/ScriptedSQL/account", params)
</programlisting>
<para>
Over the REST interface, the query filter is specified as
<literal>_queryFilter=<replaceable>filter</replaceable></literal>, 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/managed/user?_queryFilter=userName+eq+"Smith"'
</userinput></screen>
<para>
When called over REST, you must URL encode the filter expression. The
following examples show the filter expressions using the resource API and
the REST API, but do not show the URL encoding, to make them easier to read.
</para>
<para>
Note that, for generic mappings, any fields that are included in the query
filter (for example <literal>userName</literal> in the previous query), must
be explicitly defined as <emphasis>searchable</emphasis>, if you have set
the global <literal>searchableDefault</literal> to false. For more
information, see <link xlink:show="new"
xlink:href="integrators-guide#searches-with-generic-mappings"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Improving
Search Performance for Generic Mappings</citetitle></link>.
</para>
<variablelist>
<para>
The <replaceable>filter</replaceable> expression is constructed from the
building blocks shown in this section. In these expressions the simplest
<replaceable>json-pointer</replaceable> is a field of the JSON resource,
such as <literal>userName</literal> or <literal>id</literal>. A json-pointer
can, however, point to nested elements as described in the
<link xlink:show="new" xlink:href="http://tools.ietf.org/html/rfc6901">JSON
Pointer RFC</link>.
</para>
<varlistentry>
<term>Comparison expressions</term>
<listitem>
<para>
The following examples show how you can build filters using comparison
expressions.
</para>
<variablelist>
<varlistentry>
<term><literal><replaceable>json-pointer</replaceable> eq <replaceable>json-value</replaceable></literal></term>
<listitem>
<para>
Matches when the pointer equals the value, for example:
</para>
<programlisting language="javascript">
"_queryFilter" : '/givenName eq "Dan"'
</programlisting>
<para>
The following REST call returns the user name and given name of all
managed users whose first name (<literal>givenName</literal>) is "Dan".
</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=givenName+eq+"Dan"&amp;_fields=userName,givenName'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 3,
"result": [
{
"givenName": "Dan",
"userName": "dlangdon"
},
{
"givenName": "Dan",
"userName": "dcope"
},
{
"givenName": "Dan",
"userName": "dlanoway"
}
}</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><literal><replaceable>json-pointer</replaceable> co <replaceable>json-value</replaceable></literal></term>
<listitem>
<para>
Matches when the pointer contains the value, for example:
</para>
<programlisting language="javascript">
"_queryFilter" : '/givenName co "smi"'
</programlisting>
<para>
The following REST call returns the user name and given name of all
managed users whose first name (<literal>givenName</literal>) contains
"Da".
</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=givenName+co+"Da"&amp;_fields=userName,givenName'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 10,
"result": [
{
"givenName": "Dave",
"userName": "djensen"
},
{
"givenName": "David",
"userName": "dakers"
},
{
"givenName": "Dan",
"userName": "dlangdon"
},
{
"givenName": "Dan",
"userName": "dcope"
},
{
"givenName": "Dan",
"userName": "dlanoway"
},
{
"givenName": "Daniel",
"userName": "dsmith"
},
...
}</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><literal><replaceable>json-pointer</replaceable> sw <replaceable>json-value</replaceable></literal></term>
<listitem>
<para>
Matches when the pointer starts with the value, for example:
</para>
<programlisting language="javascript">
"_queryFilter" : '/sn sw "Jen"'
</programlisting>
<para>
The following REST call returns the user names of all managed users
whose last name (<literal>sn</literal>) starts with "Jen".
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
'http://localhost:8443/openidm/managed/user?_queryFilter=sn+sw+"Jen"&amp;_fields=userName'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 4,
"result": [
{
"userName": "bjensen"
},
{
"userName": "djensen"
},
{
"userName": "cjenkins"
},
{
"userName": "mjennings"
}
]
}</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><literal><replaceable>json-pointer</replaceable> lt <replaceable>json-value</replaceable></literal></term>
<listitem>
<para>
Matches when the pointer is less than the value, for example:
</para>
<programlisting language="javascript">
"_queryFilter" : '/employeeNumber lt 5000'
</programlisting>
<para>
The following REST call returns the user names of all managed users whose
<literal>employeeNumber</literal> is lower than 5000.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
'http://localhost:8443/openidm/managed/user?_queryFilter=employeeNumber+lt+5000&amp;_fields=userName,employeeNumber'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 4999,
"result": [
{
"employeeNumber": 4907,
"userName": "jnorris"
},
{
"employeeNumber": 4905,
"userName": "afrancis"
},
{
"employeeNumber": 3095,
"userName": "twhite"
},
{
"employeeNumber": 3921,
"userName": "abasson"
},
{
"employeeNumber": 2892,
"userName": "dcarter"
}
...
]
}</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><literal><replaceable>json-pointer</replaceable> le <replaceable>json-value</replaceable></literal></term>
<listitem>
<para>
Matches when the pointer is less than or equal to the value, for
example:
</para>
<programlisting language="javascript">
"_queryFilter" : '/employeeNumber le 5000'
</programlisting>
<para>
The following REST call returns the user names of all managed users whose
<literal>employeeNumber</literal> is 5000 or lower.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
'http://localhost:8443/openidm/managed/user?_queryFilter=employeeNumber+le+5000&amp;_fields=userName,employeeNumber'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 5000,
"result": [
{
"employeeNumber": 4907,
"userName": "jnorris"
},
{
"employeeNumber": 4905,
"userName": "afrancis"
},
{
"employeeNumber": 3095,
"userName": "twhite"
},
{
"employeeNumber": 3921,
"userName": "abasson"
},
{
"employeeNumber": 2892,
"userName": "dcarter"
}
...
]
}</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><literal><replaceable>json-pointer</replaceable> gt <replaceable>json-value</replaceable></literal></term>
<listitem>
<para>
Matches when the pointer is greater than the value, for example:
</para>
<programlisting language="javascript">
"_queryFilter" : '/employeeNumber gt 5000'
</programlisting>
<para>
The following REST call returns the user names of all managed users whose
<literal>employeeNumber</literal> is higher than 5000.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
'http://localhost:8443/openidm/managed/user?_queryFilter=employeeNumber+gt+5000&amp;_fields=userName,employeeNumber'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 1458,
"result": [
{
"employeeNumber": 5003,
"userName": "agilder"
},
{
"employeeNumber": 5011,
"userName": "bsmith"
},
{
"employeeNumber": 5034,
"userName": "bjensen"
},
{
"employeeNumber": 5027,
"userName": "cclarke"
},
{
"employeeNumber": 5033,
"userName": "scarter"
}
...
]
}</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><literal><replaceable>json-pointer</replaceable> ge <replaceable>json-value</replaceable></literal></term>
<listitem>
<para>
Matches when the pointer is greater than or equal to the value for
example:
</para>
<programlisting language="javascript">
"_queryFilter" : '/employeeNumber ge 5000'
</programlisting>
<para>
The following REST call returns the user names of all managed users whose
<literal>employeeNumber</literal> is 5000 or higher.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
'http://localhost:8443/openidm/managed/user?_queryFilter=employeeNumber+ge+5000&amp;_fields=userName,employeeNumber'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 1457,
"result": [
{
"employeeNumber": 5000,
"userName": "agilder"
},
{
"employeeNumber": 5011,
"userName": "bsmith"
},
{
"employeeNumber": 5034,
"userName": "bjensen"
},
{
"employeeNumber": 5027,
"userName": "cclarke"
},
{
"employeeNumber": 5033,
"userName": "scarter"
}
...
]
}</computeroutput></screen>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry>
<term>Presence expression</term>
<listitem>
<para>
<literal><replaceable>json-pointer</replaceable> pr</literal> matches any
object in which the <replaceable>json-pointer</replaceable> is present,
for example:
</para>
<programlisting language="javascript">
"_queryFilter" : '/mail pr'
</programlisting>
<para>
The following REST call returns the mail addresses for all managed users
who have a <literal>mail</literal> property in their entry.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
'http://localhost:8443/openidm/managed/user?_queryFilter=mail+pr&amp;_fields=mail'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 2,
"result": [
{
"mail": "jdoe@exampleAD.com"
},
{
"mail": "bjensen@example.com"
}
]
}</computeroutput></screen>
<para>
The presence filter is not currently supported for system objects. To
query for presence on a system object, specify any attribute that exists
for all entries, such as the <literal>uid</literal> on an LDAP system,
and use the starts with (<literal>sw</literal>) filter, with an empty
value. For example, the following query returns the <literal>uid</literal>
of all users in an LDAP system.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
'http://localhost:8443/openidm/system/ldap/account?_queryFilter=uid+sw+""&amp;_fields=uid'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 2,
"result": [
{
"uid": "jdoe"
},
{
"uid": "bjensen"
}
]
}</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term>Literal expressions</term>
<listitem>
<para>
<literal>true</literal> matches any object in the resource.
</para>
<para>
<literal>false</literal> matches no object in the resource.
</para>
<para>
For example, you can list the <literal>_id</literal> of all managed
objects 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?_queryFilter=true&amp;_fields=_id'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 2,
"result": [
{
"_id": "d2e29d5f-0d74-4d04-bcfe-b1daf508ad7c"
},
{
"_id": "709fed03-897b-4ff0-8a59-6faaa34e3af6"
}
]
}</computeroutput>
</screen>
</listitem>
</varlistentry>
<varlistentry>
<term>Complex expressions</term>
<listitem>
<para>
You can combine expressions using the boolean operators
<literal>and</literal>, <literal>or</literal>, and <literal>!</literal>
(not). The following example queries managed user objects located in
London, with last name Jensen.
</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=city+eq+"London"+and+sn+eq+"Jensen"&amp;_fields=userName,givenName,sn'&amp;_fields=userName'</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 3,
"result": [
{
"sn": "Jensen",
"givenName": "Clive",
"userName": "cjensen"
},
{
"sn": "Jensen",
"givenName": "Dave",
"userName": "djensen"
},
{
"sn": "Jensen",
"givenName": "Margaret",
"userName": "mjensen"
}
]
}</computeroutput></screen>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="paging-query-results">
<title>Paging Query Results</title>
<para>
The common filter query mechanism supports paged query results for managed
and system objects.
</para>
<para>
The following filtered query returns the first two records in an LDAP
repository, whose <literal>uid</literal> starts with <literal>b</literal>.
</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?_queryFilter=uid%20sw%20%22b%22&amp;_pageSize=2"
</userinput>
<computeroutput>
{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 2,
"result": [
{
"_id": "uid=bjensen,ou=People,dc=example,dc=com",
"sn": "Jensen",
"dn": "uid=bjensen,ou=People,dc=example,dc=com",
"givenName": "Barbara",
"description": "Created for OpenIDM",
"cn": "Barbara Jensen",
"uid": "bjensen",
"ldapGroups": [
"cn=openidm2,ou=Groups,dc=example,dc=com"
],
"mail": "bjensen@example.com",
"telephoneNumber": "1-360-229-7105"
},
{
"_id": "cn=bsmith,ou=People,dc=example,dc=com",
"sn": "Smith",
"dn": "cn=bsmith,ou=People,dc=example,dc=com",
"givenName": "Bill",
"description": null,
"cn": "bsmith",
"uid": "bsmith",
"ldapGroups": [],
"mail": "bsmith@example.com",
"telephoneNumber": "0987362837"
}
]
}</computeroutput> </screen>
<para>
Predefined queries also provide some support for paged
results, useful, for example, for UI display purposes. Predefined queries
must be configured to support paging, in the repository configuration. For
example:
</para>
<screen>"query-all-ids" : "select _openidm_id from ${unquoted:_resource} SKIP ${unquoted:_pagedResultsOffset} LIMIT ${unquoted:_pageSize}",</screen>
<para>
This query configuration enables the paging parameters to be used, for
example, in a query such as the following:
</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 GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids&amp;_pageSize=2&amp;_pagedResultsOffset=3"</userinput>
<computeroutput>{
"remainingPagedResults": 2,
"pagedResultsCookie": "5",
"resultCount": 2,
"result": [
{
"_rev": "0",
"_id": "b980999e-aa5c-4655-b2a0-08731b64e0ba"
},
{
"_rev": "0",
"_id": "c72b9c00-1e2c-4139-9e7f-fb9fb822db96"
}
]
}</computeroutput> </screen>
<variablelist>
<para>
The following paging parameters are supported:
</para>
<varlistentry>
<term><literal>_pagedResultsCookie</literal></term>
<listitem>
<para>
Opaque cookie used by the server to keep track of the position
in the search results. The format of the cookie is a string value.
</para>
<para>
The server provides the cookie value on the first request. You should then
supply the cookie value in subsequent requests until the server returns a
null cookie, meaning that the final page of results has been returned.
</para>
<para>
Paged results are enabled only if the <literal>_pageSize</literal> is a
non-zero integer.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>_pagedResultsOffset</literal></term>
<listitem>
<para>
Specifies the index within the result set of the number of records to be
skipped before the first result is returned. The format of the
<literal>_pagedResultsOffset</literal> is an integer value. When the value
of <literal>_pagedResultsOffset</literal> is greater than or equal to 1,
the server returns pages, starting after the specified index.
</para>
<para>
This request assumes that the <literal>_pageSize</literal> is set, and not
equal to zero.
</para>
<para>
For example, if the result set includes 10 records, the
<literal>_pageSize</literal> is 2, and the
<literal>_pagedResultsOffset</literal> is 6, the server skips the first 6
records, then returns 2 records, 7 and 8. The
<literal>_pagedResultsCookie</literal> value would then be 8 (the index of
the last returned record) and the <literal>_remainingPagedResults</literal>
value would be 2, the last two records (9 and 10) that have not yet been
returned.
</para>
<para>
If the offset points to a page beyond the last of the search results, the
result set returned is empty.
</para>
<para>
Note that the <literal>_remainingPagedResults</literal> parameter is not
supported for all queries. Where it is not supported, the returned value
is always <literal>-1</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>_pageSize</literal></term>
<listitem>
<para>
An optional parameter indicating that query results should be returned in
pages of the specified size. For all paged result requests other than the
initial request, a cookie should be provided with the query request.
</para>
<para>
The default behavior is not to return paged query results. If set, this
parameter should be an integer value, greater than zero.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sorting-query-results">
<title>Sorting Query Results</title>
<para>
For common filter query expressions, you can sort the results of a query,
using the <literal>_sortKeys</literal> parameter. This parameter takes a
comma-separated list as a value and orders the way in which the JSON result
is returned, based on this list.
</para>
<para>
The <literal>_sortKeys</literal> parameter is not supported for predefined
queries.
</para>
<para>
The following query returns all users with the <literal>givenName</literal>
<literal>Dan</literal>, and sorts the results alphabetically, according to
surname (<literal>sn</literal>).
</para>
<screen>$ <userinput>
'https://localhost:8443/openidm/system/ldap/account?_queryFilter=givenName+eq+"Dan"&amp;_fields=givenName,sn&amp;_sortKeys=sn'
</userinput>
<computeroutput>
{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 3,
"result": [
{
"sn": "Cope",
"givenName": "Dan"
},
{
"sn": "Langdon",
"givenName": "Dan"
},
{
"sn": "Lanoway",
"givenName": "Dan"
}
]
} </computeroutput>
</screen>
</section>
</section>
</chapter>