Performing RESTful OperationsHTTPJSONRESTOpenDJ lets you access directory data as JSON resources over HTTP.
This chapter demonstrates basic RESTful client operations using the
default configuration and sample directory data imported into OpenDJ from
Example.ldif. Before trying the examples, enable HTTP access to
OpenDJ directory server as described in procedure, To Set Up REST
Access to OpenDJ Directory Server.Understanding the OpenDJ REST APIThe OpenDJ REST API is built on a common ForgeRock HTTP-based REST API
for interacting with JSON Resources. APIs built on this common layer all let
you perform the following operations.CreateAdd a resource that does not yet existReadRetrieve a single resourceUpdateReplace an existing resourceDeleteRemove an existing resourcePatchModify part of an existing resourceActionPerform a predefined actionQueryList a set of resourcesThe present implementation in OpenDJ maps JSON resources onto LDAP
entries, meaning REST clients can in principle do just about anything an
LDAP client can do with directory data.In addition to query string parameters that depend on the operation,
the examples in this chapter make use of the following parameters that
apply to the JSON resource returned for all operations._fields=field[,...]Retain only the specified fields in the JSON resource returned._prettyPrint=true|falseMake the JSON resource returned easy for humans to read.Authenticating Over RESTTODO, https://bugster.forgerock.org/jira/browse/OPENDJ-828Creating ResourcesThere are two ways to create resources.To create a resource using an ID that you specify, perform an HTTP PUT
request with headers Content-Type: application/json and
If-None-Match: *, and the JSON content of your
resource.The following example creates a new user entry with ID
newuser.$ curl
--request PUT
--user kvaughan:bribery
--header "Content-Type: application/json"
--header "If-None-Match: *"
--data '{
"_id": "newuser",
"contactInformation": {
"telephoneNumber": "+1 408 555 1212",
"emailAddress": "newuser@example.com"
},
"name": {
"familyName": "New",
"givenName": "User"
},
"displayName": "New User",
"manager": [
{
"_id": "kvaughan",
"displayName": "Kirsten Vaughan"
}
]
}'
http://opendj.example.com:8080/users/newuser?_prettyPrint=true
{
"_rev" : "000000005b337348",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 1212",
"emailAddress" : "newuser@example.com"
},
"_id" : "newuser",
"name" : {
"familyName" : "New",
"givenName" : "User"
},
"userName" : "newuser@example.com",
"displayName" : "New User",
"meta" : {
"created" : "2013-04-11T09:58:27Z"
},
"manager" : [ {
"_id" : "kvaughan",
"displayName" : "Kirsten Vaughan"
} ]
}To create a resource letting the server choose the ID, perform an HTTP
POST with _action=create as described in
.Reading a ResourceTo read a resource, perform an HTTP GET.$ curl
--request GET
--user kvaughan:bribery
http://opendj.example.com:8080/users/newuser?_prettyPrint=true
{
"_rev" : "000000005b337348",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 1212",
"emailAddress" : "newuser@example.com"
},
"_id" : "newuser",
"name" : {
"familyName" : "New",
"givenName" : "User"
},
"userName" : "newuser@example.com",
"displayName" : "New User",
"meta" : {
"created" : "2013-04-11T09:58:27Z"
},
"manager" : [ {
"_id" : "kvaughan",
"displayName" : "Kirsten Vaughan"
} ]
}Updating ResourcesTo update a resource, perform an HTTP PUT with the changes to the
resource. For read-only fields, either include unmodified versions, or omit
them from your updated version.The following example adds a manager for Sam Carter.$ curl
--request PUT
--user kvaughan:bribery
--header "Content-Type: application/json"
--data '{
"contactInformation": {
"telephoneNumber": "+1 408 555 4798",
"emailAddress": "scarter@example.com"
},
"name": {
"familyName": "Carter",
"givenName": "Sam"
},
"userName": "scarter@example.com",
"displayName": "Sam Carter",
"groups": [
{
"_id": "Accounting Managers"
}
],
"manager": [
{
"_id": "trigden",
"displayName": "Torrey Rigden"
}
]
}'
http://opendj.example.com:8080/users/scarter?_prettyPrint=true
{
"_rev" : "00000000a1923db2",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 4798",
"emailAddress" : "scarter@example.com"
},
"_id" : "scarter",
"name" : {
"familyName" : "Carter",
"givenName" : "Sam"
},
"userName" : "scarter@example.com",
"displayName" : "Sam Carter",
"manager" : [ {
"_id" : "trigden",
"displayName" : "Torrey Rigden"
} ],
"meta" : {
"lastModified" : "2013-04-12T07:42:34Z"
},
"groups" : [ {
"_id" : "Accounting Managers"
} ]
}To update a resource only if the resource matches a particular version,
use an If-Match: revision
header. $ curl
--user kvaughan:bribery
http://opendj.example.com:8080/users/scarter?_fields=_rev
{"_rev":"00000000b017c5b8"}
$ curl
--request PUT
--user kvaughan:bribery
--header "If-Match: 00000000b017c5b8"
--header "Content-Type: application/json"
--data '{
"contactInformation": {
"telephoneNumber": "+1 408 555 1212",
"emailAddress": "scarter@example.com"
},
"name": {
"familyName": "Carter",
"givenName": "Sam"
},
"userName": "scarter@example.com",
"displayName": "Sam Carter",
"groups": [
{
"_id": "Accounting Managers"
}
],
"manager": [
{
"_id": "trigden",
"displayName": "Torrey Rigden"
}
]
}'
http://opendj.example.com:8080/users/scarter?_prettyPrint=true
{
"_rev" : "00000000a1ee3da3",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 1212",
"emailAddress" : "scarter@example.com"
},
"_id" : "scarter",
"name" : {
"familyName" : "Carter",
"givenName" : "Sam"
},
"userName" : "scarter@example.com",
"displayName" : "Sam Carter",
"meta" : {
"lastModified" : "2013-04-12T07:47:45Z"
},
"groups" : [ {
"_id" : "Accounting Managers"
} ],
"manager" : [ {
"_id" : "trigden",
"displayName" : "Torrey Rigden"
} ]
}Deleting ResourcesTo delete a resource, perform an HTTP DELETE on the resource URL.
On success, the operation returns the resource you deleted.$ curl
--request DELETE
--user kvaughan:bribery
http://opendj.example.com:8080/users/newuser?_prettyPrint=true
{
"_rev" : "000000003a5f3cb2",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 1212",
"emailAddress" : "newuser@example.com"
},
"_id" : "newuser",
"name" : {
"familyName" : "New",
"givenName" : "User"
},
"userName" : "newuser@example.com",
"displayName" : "New User",
"meta" : {
"created" : "2013-04-11T09:58:27Z"
},
"manager" : [ {
"_id" : "kvaughan",
"displayName" : "Kirsten Vaughan"
} ]
}To delete a resource only if the resource matches a particular version,
use an If-Match: revision
header.$ curl
--user kvaughan:bribery
http://opendj.example.com:8080/users/newuser?_fields=_rev
{"_rev":"000000006d8d7358"}
$ curl
--request DELETE
--user kvaughan:bribery
--header "If-Match: 000000006d8d7358"
http://opendj.example.com:8080/users/newuser?_prettyPrint=true
{
"_rev" : "00000000383f3cae",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 1212",
"emailAddress" : "newuser@example.com"
},
"_id" : "newuser",
"name" : {
"familyName" : "New",
"givenName" : "User"
},
"userName" : "newuser@example.com",
"displayName" : "New User",
"meta" : {
"created" : "2013-04-11T12:48:48Z"
},
"manager" : [ {
"_id" : "kvaughan",
"displayName" : "Kirsten Vaughan"
} ]
}To delete a resource and all its children, you must change the
configuration, get the REST LDAP gateway or HTTP Connection Handler to
reload its configuration, and perform the operation as a user who has the
access rights required. The following steps show one way to do this with
the HTTP Connection Handler.In this case the LDAP view of the user to delete shows two child
entries.$ ldapsearch --port 1389 --baseDN uid=nbohr,ou=people,dc=example,dc=com "(&)" dn
dn: uid=nbohr,ou=People,dc=example,dc=com
dn: cn=quantum dot,uid=nbohr,ou=People,dc=example,dc=com
dn: cn=qubit generator,uid=nbohr,ou=People,dc=example,dc=comIn the configuration file for the HTTP Connection Handler, by default
/path/to/OpenDJ/config/http-config.json, set
"useSubtreeDelete" : true.After this change, only users who have access to request a tree
delete can delete resources.Force the HTTP Connection Handler to reread its configuration.$ dsconfig
set-connection-handler-prop
--hostname opendj.example.com
--port 4444
--bindDN "cn=Directory Manager"
--bindPassword password
--handler-name "HTTP Connection Handler"
--set enabled:false
--no-prompt
$ dsconfig
set-connection-handler-prop
--hostname opendj.example.com
--port 4444
--bindDN "cn=Directory Manager"
--bindPassword password
--handler-name "HTTP Connection Handler"
--set enabled:true
--no-promptDelete as a user who has rights to perform a subtree delete on
the resource.$ curl
--request DELETE
--user kvaughan:bribery
http://opendj.example.com:8080/users/nbohr?_prettyPrint=true
{
"_rev" : "000000003d912113",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 1212",
"emailAddress" : "nbohr@example.com"
},
"_id" : "nbohr",
"name" : {
"familyName" : "Bohr",
"givenName" : "Niels"
},
"userName" : "nbohr@example.com",
"displayName" : "Niels Bohr"
}Patching ResourcesTODO, https://bugster.forgerock.org/jira/browse/CREST-3Using ActionsOpenDJ implements an action that lets the server choose the resource ID
on creation. To use this action, perform an HTTP POST with header
Content-Type: application/json,
_action=create in the query string, and the JSON content of
your resource.The following example creates a new user entry. Lines are folded for
readability.TODO, fix pending https://bugster.forgerock.org/jira/browse/OPENDJ-775$ curl
--request POST
--user kvaughan:bribery
--header "Content-Type: application/json"
--data '{
"_id": "newuser",
"contactInformation": {
"telephoneNumber": "+1 408 555 1212",
"emailAddress": "newuser@example.com"
},
"name": {
"familyName": "New",
"givenName": "User"
},
"displayName": "New User",
"manager": [
{
"_id": "kvaughan",
"displayName": "Kirsten Vaughan"
}
]
}'
"http://opendj.example.com:8080/users?_action=create&_prettyPrint=true"
{
"_rev" : "0000000034a23ca7",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 1212",
"emailAddress" : "newuser@example.com"
},
"_id" : "newuser",
"name" : {
"familyName" : "New",
"givenName" : "User"
},
"userName" : "newuser@example.com",
"displayName" : "New User",
"meta" : {
"created" : "2013-04-11T11:19:08Z"
},
"manager" : [ {
"_id" : "kvaughan",
"displayName" : "Kirsten Vaughan"
} ]
}TODO, https://bugster.forgerock.org/jira/browse/OPENDJ-695Querying Resource CollectionsTo query resource collections, perform an HTTP GET with a
_queryFilter=filter parameter
in your query string.For query operations, your filter
expressions are constructed from the following building blocks.
Make sure you URL encode the filter expressions, which are shown here
without URL encoding to make them easier to read.In these expressions the simplest
json-pointer is a field of the JSON resource,
such as userName or id. A
json-pointer can however point to nested
elements as described in the JSON
Pointer Internet-Draft.Comparison expressionsYou can build filters using the following comparison expressions.Request URLs are folded in the following examples to make them
easier to read.json-pointer eq json-valueMatches when the pointer equals the value, as in the following
example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=userName+eq+"bjensen@example.com"&_prettyPrint=true'
{
"result" : [ {
"_rev" : "00000000315fb731",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"manager" : [ {
"_id" : "trigden",
"displayName" : "Torrey Rigden"
} ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 1862",
"emailAddress" : "bjensen@example.com"
},
"_id" : "bjensen",
"name" : {
"familyName" : "Jensen",
"givenName" : "Barbara"
},
"userName" : "bjensen@example.com",
"displayName" : "Barbara Jensen"
} ],
"resultCount" : 1,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}json-pointer co json-valueMatches when the pointer contains the value, as in the following
example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=userName+co+"jensen"&_fields=userName&_prettyPrint=true'
{
"result" : [ {
"userName" : "ajensen@example.com"
}, {
"userName" : "bjensen@example.com"
}, {
"userName" : "gjensen@example.com"
}, {
"userName" : "jjensen@example.com"
}, {
"userName" : "kjensen@example.com"
}, {
"userName" : "rjensen@example.com"
}, {
"userName" : "tjensen@example.com"
} ],
"resultCount" : 7,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}json-pointer sw json-valueMatches when the pointer starts with the value, as in the
following example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=userName+sw+"ab"&_fields=userName&_prettyPrint=true'
{
"result" : [ {
"userName" : "abarnes@example.com"
}, {
"userName" : "abergin@example.com"
} ],
"resultCount" : 2,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}json-pointer lt json-valueMatches when the pointer is less than the value, as in the
following example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=userName+lt+"ac"&_fields=userName&_prettyPrint=true'
{
"result" : [ {
"userName" : "abarnes@example.com"
}, {
"userName" : "abergin@example.com"
} ],
"resultCount" : 2,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}json-pointer le json-valueMatches when the pointer is less than or equal to the value, as
in the following example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=userName+le+"ad"&_fields=userName&_prettyPrint=true'
{
"result" : [ {
"userName" : "abarnes@example.com"
}, {
"userName" : "abergin@example.com"
}, {
"userName" : "achassin@example.com"
} ],
"resultCount" : 3,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}json-pointer gt json-valueMatches when the pointer is greater than the value, as in the
following example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=userName+gt+"tt"&_fields=userName&_prettyPrint=true'
{
"result" : [ {
"userName" : "ttully@example.com"
}, {
"userName" : "tward@example.com"
}, {
"userName" : "wlutz@example.com"
} ],
"resultCount" : 3,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}json-pointer ge json-valueMatches when the pointer is greater than or equal to the value,
as in the following example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=userName+ge+"tw"&_fields=userName&_prettyPrint=true'
{
"result" : [ {
"userName" : "tward@example.com"
}, {
"userName" : "wlutz@example.com"
} ],
"resultCount" : 2,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}Presence expressionjson-pointer pr matches
any resource on which the json-pointer is
present, as in the following example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=userName%20pr&_prettyPrint=true'
{
"result" : [ {
"_rev" : "000000002210a544",
"schemas" : [ "urn:scim:schemas:core:1.0" ],
"manager" : [ {
"_id" : "scarter",
"displayName" : "Sam Carter"
} ],
"contactInformation" : {
"telephoneNumber" : "+1 408 555 9445",
"emailAddress" : "abarnes@example.com"
},
"_id" : "abarnes",
"name" : {
"familyName" : "Barnes",
"givenName" : "Anne-Louise"
},
"userName" : "abarnes@example.com",
"displayName" : "Anne-Louise Barnes"
},... many entries omitted ...
"_id" : "newuser",
"name" : {
"familyName" : "New",
"givenName" : "User"
},
"userName" : "newuser@example.com",
"displayName" : "New User",
"meta" : {
"created" : "2013-03-26T10:52:42Z"
}
} ],
"resultCount" : 152,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}Literal expressionstrue matches any resource in the collection.false matches no resource in the collection.In other words you can list all resources in a collection as in the
following example.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/groups?_queryFilter=true&_fields=displayName&_prettyPrint=true'
{
"result" : [ {
"displayName" : "Accounting Managers"
}, {
"displayName" : "Directory Administrators"
}, {
"displayName" : "HR Managers"
}, {
"displayName" : "PD Managers"
}, {
"displayName" : "QA Managers"
} ],
"resultCount" : 5,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}Complex expressionsYou can combine expressions using boolean operators
and, or, and !
(not), using parentheses,
(expression), to group
expressions. The following example queries resources with last name
Jensen and manager name starting with Bar. Notice that
the filters use the JSON pointers name/familyName and
manager/displayName to identify the fields that are
nested inside the name and manager
objects.$ curl --user kvaughan:bribery 'http://opendj.example.com:8080
/users?_queryFilter=(userName+co+"jensen"+and+manager/displayName+sw+"Sam")
&_fields=displayName&_prettyPrint=true'
{
"result" : [ {
"displayName" : "Jody Jensen"
}, {
"displayName" : "Ted Jensen"
} ],
"resultCount" : 2,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}You can have the server sort JSON resources before it returns them by
using the _sortKeys[+-]=field[,...]
query string. TODO, pending implementation https://bugster.forgerock.org/jira/browse/OPENDJ-702You can page through search results using the following query string
parameters.TODO, pending implementation https://bugster.forgerock.org/jira/browse/OPENDJ-701__pagedResultsCookie=stringTODO__pagedResultsOffset=stringTODO__pagedResultsCookie=stringTODO