CRUDPAQ

Maybe you noticed that Matt has been building a foundation for common ForgeRock REST APIs. What makes the APIs common is that they all let you do the same seven kinds of operations.

  1. Create: Add a resource that does not yet exist
  2. Read: Retrieve a single resource
  3. Update: Replace an existing resource
  4. Delete: Remove an existing resource
  5. Patch: Modify part of an existing resource
  6. Action: Perform a predefined action
  7. Query: List a set of resources

When you hear someone from ForgeRock talking about CRUDPAQ, there’s nothing dirty involved. Just a mnemonic device.

(Note: In practice, action operations depend on the resource server, so actions might differ from server to server. Also, some bits of work remain. For example, patch is still to be finished as of this writing.)

Matt put together a JSON Resource Java library. With that he built a JSON Resource Servlet, which implements an in-memory store for your resources. (See the project page for instructions on getting JSON Resource Servlet up and running.) JSON Resource Servlet provides a simple example of how these common REST APIs are likely to look and feel.

Matt included two endpoints by default, /users and /groups. Objects in this version do not have schema, so you can add whatever you like. I’ve played with arrays of SCIM-like users and groups based on the traditional example data we use in the directory server world.

The advantage of this is that it’s all language independent. Take your pick.

After getting a rise out of Jake’s cool work, especially on the OpenIDM UI, I felt it was high time to learn some JavaScript.

Even with my beginner’s confusion about JavaScript, it did not take long to write CRUD and Q functions for use in building a web page. (Creating a page that doesn’t look like I pulled it out of a time capsule from 1996 is a different story, however. My stance with respect to modern web development is 2nd or 3rd order ignorance, depending on the topic.) There are slicker ways to do this, but as you can see, it is not hard to…

Create a resource from an object and a resource URI (ending in the resource ID like /users/bjensen, or more likely /users/e7fa64c0-70dc-47fb-b102-7106ee480421):

function create(object, uri) {
    var xhr = new XMLHttpRequest();
    xhr.open('PUT', uri, false);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.setRequestHeader("If-None-Match", "*");
    xhr.send(JSON.stringify(object));
    return xhr.responseText;
}

Read a resource, optionally limiting the resource fields in the response (check the response field “_id” for the resource ID):

function read(uri, fields) {
    fields = (typeof fields === "undefined") ? [] : fields;

    var args = "";
    if (fields.length > 0) {
        args = "?_fields=" + fields[0];
        for (var i = 1; i < fields.length; i++) {
            args = args + "," + fields[i];
        }
    }
    uri = uri + args;

    var xhr = new XMLHttpRequest();
    xhr.open('GET', uri, false);
    xhr.send("");
    return xhr.responseText;
}

Update a resource, for which you need the revision (check the resource “_rev” field):

function update(object, revision, uri) {
    var xhr = new XMLHttpRequest();
    xhr.open('PUT', uri, false);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.setRequestHeader("If-Match", revision);
    xhr.send(JSON.stringify(object));
    return xhr.responseText;
}

Delete a resource:

function remove(uri) { // delete is a keyword
    var xhr = new XMLHttpRequest();
    xhr.open('DELETE', uri, false);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.send("");
    return xhr.responseText;
}

Query resources. Query lets you do a lot more than this example (filters, sorting, paging, … Scroll down the JSON Resource Servlet page to the section on Querying/listing resources). This one just lists resources. Here containerUri is /users, or /groups:

function queryObjects(containerUri, fields) {
    fields = (typeof fields === "undefined") ? [] : fields;

    var query = containerUri + "?_filter=true";
    var args = "";
    if (fields.length > 0) {
        args = "&_fields=" + fields[0];
        for (var i = 1; i < fields.length; i++) {
            args = args + "," + fields[i];
        }
        query = query + args;
    }

    var xhr = new XMLHttpRequest();
    xhr.open('GET', query, false);
    xhr.send("");

    var allObjects = [];
    if (xhr.status === 200) { // OK
        allObjects = JSON.parse(xhr.responseText);
        if (allObjects.result.length > 0) {
            allObjects = allObjects.result;
        } else {
            allObjects = [];
        }
    }
    return allObjects;
}

Not shown here are actions. The JSON Resource Servlet for example lets you create a resource and let the servlet create the ID. (Hint: Use a POST with ?_action=create to the container URI.)

As you can see, the basic operations are fairly easy to use.

By the way, not all ForgeRock REST APIs will look like this. The REST API for OAuth 2.0 in OpenAM will not, for example, because that API is already clearly defined at the IETF. But there’s a good chance that many APIs will follow this pattern.

3 thoughts on “CRUDPAQ

  1. Pingback: OpenDJ: REST to LDAP Gateway | Margin Notes 2.0

  2. Pingback: OpenAM: New REST APIs | Margin Notes 2.0

  3. Pingback: About REST APIs and API Descriptors – Margin Notes 2.0

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.