# Specification of the CREST HTTP protocol

CREST defines 6 core operations, Create, Read, Update, Delete, Patch, and Query, as well
as an extensible operation called Action. These are referred to collectively as CRUDPAQ.
Each operation comprises of a request and one or more responses. Each request defines
the set of paramepters that may be used with it. Of most interest to developers (you!)
is how CREST maps to HTTP. In particular, how the CREST operations map to HTTP methods,
headers, query parameters, content, and status codes.

## Create (server provided resource ID)

A POST create request should be used when the resource to be created will have a server
provided resource ID (e.g. a UUID). It may also be used in cases where the resource ID
is client provided, but only as long as the resource ID is included as a field within the
new resource.

POST create requests should target the resource container and must include the parameter
`_action=create`.

<table>
    <tr>
        <th>Method</th>
        <td><tt>POST</tt></td>
    </tr>
    <tr>
        <th>Parameter</th>
        <td><p><i>See common parameters</i></p></td>
    </tr>
    <tr>
        <td>
            <tt>_action=create</tt>
        </td>
        <td>
            <p>
                Mandatory parameter which must be equal
                to the value "create" indicating that this is a
                request to create a new resource.
            </p>
        </td>
    </tr>
    <tr>
        <th>Content</th>
        <td>
            <p>The JSON representation of the resource to be created.</p>
        </td>
    </tr>
    <tr>
        <th>Returns</th>
        <td>
            <p>The JSON representation of the resource that was created.</p>
        </td>
    </tr>
</table>

Example:

```
POST /users?_action=create HTTP/1.1
Host: example.com
Accept: application/json
Content-Type: application/json
Content-Length: ...
{
  "uid" : "alice",
  "email" : "alice@example.com"
}
```

## Create (client provided resource ID)

A PUT create request should be used when the resource to be
created has a known resource ID. The resource ID is
specified as part of the target resource name, and may also
be included as a field within the new resource, in which
case the two must be equivalent.

PUT create requests should target the new resource and
include the HTTP header `If-None-Match: *`.

<table>
    <tr>
        <th>Method</th>
        <td><tt>PUT</tt></td>
    </tr>
    <tr>
        <th>Parameter</th>
        <td><p><i>See common parameters</i></p></td>
    </tr>
    <tr>
        <th>Content</th>
        <td>
            <p>The JSON representation of the resource to be created.</p>
        </td>
    </tr>
    <tr>
        <th>Returns</th>
        <td>
            <p>The JSON representation of the resource that was created.</p>
        </td>
    </tr>
</table>

Example:

```
PUT /users/1 HTTP/1.1
Host: example.com
Accept: application/json
Content-Type: application/json
Content-Length: ...
If-None-Match: *
{
  "uid" : "alice",
  "email" : "alice@example.com"
}
```

## Read

To read an existing resource send a GET request targeting
the resource to be read.

<table>
    <tr>
        <th>Method</th>
        <td><tt>GET</tt></td>
    </tr>
    <tr>
        <th>Parameter</th>
        <td><p><i>See common parameters</i></p></td>
    </tr>
    <tr>
        <td>
            <tt>_mimeType=<i>mimeType</i></tt>
        </td>
        <td>
            <p>A string that identifies the media type for the response content.
            When this parameter is used only 1 field value may be returned using the <tt>_fields</tt>
            parameter.</p>
        </td>
    </tr>
    <tr>
        <th>Content</th>
        <td>
            <p>N/A</p>
        </td>
    </tr>
    <tr>
        <th>Returns</th>
        <td>
            <p>The JSON representation of the resource that was read if the <tt>_mimeType</tt> parameter
            is not used. Otherwise the requested resource field is returned with the content type specified in the
                <tt>_mimeType</tt> parameter</p>
        </td>
    </tr>
</table>

Example:

```
GET /users/1  HTTP/1.1
Host: example.com
Accept: application/json
```

## Update

To replace the contents of an existing resource send a PUT
request targeting the resource and optionally include
the HTTP header `If-Match` specifying the version if
MVCC is needed.

<table>
    <tr>
        <th>Method</th>
        <td><p><tt>PUT</tt></p></td>
    </tr>
    <tr>
        <th>Parameter</th>
        <td><p><i>See common parameters</i></p></td>
    </tr>
    <tr>
        <th>Content</th>
        <td>
            <p>The JSON representation of the resource to be
            updated.</p>
        </td>
    </tr>
    <tr>
        <th>Returns</th>
        <td>
            <p>The JSON representation of the resource that was
            updated.</p>
        </td>
    </tr>
</table>

Example:

```
PUT /users/1  HTTP/1.1
Host: example.com
Accept: application/json
Content-Type: application/json
Content-Length: ...
If-Match: "1"
{
  "uid" : "alice",
  "email" : "alice@example.com"
}
```

## Delete

To delete an existing resource send a DELETE request targeting
the resource to be deleted and optionally include
the HTTP header `If-Match` specifying the version if
MVCC is needed.

<table>
    <tr>
        <th>Method</th>
        <td><tt>DELETE</tt></td>
    </tr>
    <tr>
        <th>Parameter</th>
        <td><p><i>See common parameters</i></p></td>
    </tr>
    <tr>
        <th>Content</th>
        <td>
            <p>N/A</p>
        </td>
    </tr>
    <tr>
        <th>Returns</th>
        <td>
            <p>The JSON representation of the resource that was deleted.</p>
        </td>
    </tr>
</table>

Example:

```
DELETE /users/1  HTTP/1.1
Host: example.com
Accept: application/json
If-Match: "1"
```

## Patch

To partially modify the contents of an existing resource send a PATCH
request targeting the resource and optionally include
the HTTP header "If-Match" specifying the version if
MVCC is needed. The content of the request is a JSON array whose
elements are the modifications which should be applied to the resource.

<table>
    <tr>
        <th>Method</th>
        <td><p><tt>PATCH</tt></p></td>
    </tr>
    <tr>
        <th>Parameter</th>
        <td><p><i>See common parameters</i></p></td>
    </tr>
    <tr>
        <th>Content</th>
        <td>
            <p>A JSON array whose elements are the modifications
            which should be applied to the resource.</p>
        </td>
    </tr>
    <tr>
        <th>Returns</th>
        <td>
            <p>The JSON representation of the resource that was
            updated.</p>
        </td>
    </tr>
</table>

Example:

```
PATCH /users/1  HTTP/1.1
Host: example.com
Accept: application/json
Content-Type: application/json
Content-Length: ...
If-Match: "1"
[
    {
        "operation" : "add",
        "field"     : "roles",
        "value"     : "admin"
    },
    {
        "operation" : "remove",
        "field"     : "field/subfield",
        "value"     : "valueToBeRemoved"
    }
]
```

## Action

Some resources may support additional operations which can
performed against them. These operations are performed by
sending a POST request specifying the type of action to be
performed using the `_action` parameter. The
request may include zero or more implementation specific
parameters.

Note that the action identifier `create` is reserved
exclusively for resource creation.

<table>
    <tr>
        <th>Method</th>
        <td><tt>POST</tt></td>
    </tr>
    <tr>
        <th>Parameter</th>
        <td><p><i>See common parameters</i></p></td>
    </tr>
    <tr>
        <td>
            <tt>_action=<i>ID</i></tt>
        </td>
        <td>
            <p>Mandatory parameter which identifying the type of
            action to be performed against the resource.</p>
        </td>
    </tr>
    <tr>
        <td>
            <tt><i>arg1</i>=<i>value1</i>&amp;<i>arg2</i>=<i>value2</i>&amp;...&amp;<i>argn</i>=<i>valuen</i></tt>
        </td>
        <td>
            <p>Additional parameters supported by the action. By
            convention argument names should not begin with an
            underscore.</p>
        </td>
    </tr>
    <tr>
        <th>Content</th>
        <td>
            <p>The action specified JSON request content if
            applicable.</p>
        </td>
    </tr>
    <tr>
        <th>Returns</th>
        <td>
            <p>The action specified JSON response content if
            applicable.</p>
        </td>
    </tr>
</table>

Example:

```
POST /tasks/1?_action=cancel  HTTP/1.1
Host: example.com
Accept: application/json
```

## Query

To search or list the resources contained within a resource
container send a GET request targeting the resource
container and including either a `_queryFilter` or
`_queryId` parameter.

<table>
    <tr>
        <th>Method</th>
        <td><tt>GET</tt></td>
    </tr>
    <tr>
        <th>Parameter</th>
        <td><p><i>See common parameters</i></p></td>
    </tr>
    <tr>
        <td>
            <tt>_queryFilter=<i>FILTER</i></tt>
        </td>
        <td>
            <p>A filter expression which will be used to determine
            whether or not a resource should be included in the
            returned results. The filter format is described in the
            Javadoc for the <a
            href="http://commons.forgerock.org/forgerock-rest/json-resource/apidocs/org/forgerock/json/resource/QueryFilter.html"><tt>QueryFilter</tt></a>
            class. This parameter is mandatory if
            <tt>_queryId</tt> is not specified.</p>
        </td>
    </tr>
    <tr>
        <td>
            <tt>_queryId=<i>ID</i></tt>
        </td>
        <td>
            <p>A string identifying a server side "stored" query.
            This parameter is mandatory if <tt>_queryFilter</tt>
            is not specified.</p>
        </td>
    </tr>
    <tr>
        <td>
            <tt>_sortKeys=<i>[+-]FIELD,...</i></tt>
        </td>
        <td>
            <p>Optional parameter containing a comma separated
            list of field references specifying which fields
            of the targeted JSON resources should be used as
            sort keys. A sort key is a JSON pointer optionally
            prefixed with a "+" or "-" character indicating
            whether the key is to be sorted in ascending or
            descending order. Default is to not sort results.</p>
        </td>
    </tr>
    <tr>
        <td>
            <tt>_pagedResultsCookie=<i>STRING</i></tt>
        </td>
        <td>
            <p>
                Optional opaque cookie which is used by the
                server to track its position in the
                set of query results. Paged results will be
                enabled if and only if the <tt>_pageSize</tt> is
                non-zero.
            </p>
            <p>
                The cookie must be not be specified in the
                initial query request. Subsequent query
                requests must include the cookie returned with
                the previous query result
                <tt>pagedResultsCookie</tt> field, until the
                server returns a <tt>null</tt> cookie indicating
                that the final page of results has been returned.
            </p>
            <p>
                Default behavior is to not return paged query
                results.
            </p>
        </td>
    </tr>
    <tr>
        <td>
            <tt>_pagedResultsOffset=<i>INTEGER</i></tt>
        </td>
        <td>
            <p>
                Optional parameter specifying the index within
                the result set of the first result which should
                be returned. Paged results will be enabled if
                and only if the page size is non-zero. If the
                parameter is not present or a value less than 1
                is specified then the page following the last
                page returned will be returned. A value equal
                to or greater than 1 indicates that a specific
                page should be returned starting from the position
                specified.
            </p>
            <p>
                Default behavior is to return the page following the
                previous returned page.
            </p>
        </td>
    </tr>
    <tr>
        <td>
            <tt>_pageSize=<i>INTEGER</i></tt>
        </td>
        <td>
            <p>
                Optional parameter indicating that query results are
                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.
            </p>
            <p>
                Default behavior is to not return paged
                query results.
            </p>
        </td>
    </tr>
    <tr>
        <td>
            <tt><i>arg1</i>=<i>value1</i>&amp;<i>arg2</i>=<i>value2</i>&amp;...&amp;<i>argn</i>=<i>valuen</i></tt>
        </td>
        <td>
            <p>Additional parameters supported by the stored query.
            By convention argument names should not begin with
            an underscore. It is an error to include additional
            parameters if a <tt>_filter</tt> is specified.</p>
        </td>
    </tr>
    <tr>
        <th>Content</th>
        <td>
            <p>N/A</p>
        </td>
    </tr>
    <tr>
        <th>Returns</th>
        <td>
            <p>
                A JSON object containing the following three fields:
            </p>
            <ul>
                <li>
                    <b>results</b> - an array containing the
                    matching resources, or next page of matching
                    resources if paged results have been
                    requested.
                </li>
                <li>
                    <b>pagedResultsCookie</b> - the opaque
                    cookie which should be included with the
                    next paged results query if paged results
                    have been requested, otherwise <tt>null</tt>.
                </li>
                <li>
                    <b>remainingPagedResults</b> - an estimate
                    of the number of remaining paged results, or
                    <tt>-1</tt> if the number is not known, or
                    if paged results have not been requested.
                </li>
            </ul>
        </td>
    </tr>
</table>

Example:

```
GET /users?_queryId=all  HTTP/1.1
Host: example.com
Accept: application/json
```

## Common request parameters

The following table lists the common HTTP request parameters
which may be used with any type of request.

<table>
    <tr>
        <th>Parameter</th>
        <th>Description</th>
    </tr>
    <tr>
        <td>
            <tt>_fields=FIELD,...</tt>
        </td>
        <td>
            <p>
                Optional parameter containing a comma separated
                list of field references specifying which fields
                of the targeted JSON resource should be returned.
            </p>
            <p>
                Default is to return all fields.
            </p>
        </td>
    </tr>
    <tr>
        <td>
            <tt>_prettyPrint=true|false</tt>
        </td>
        <td>
            <p>
                Optional parameter requesting that the returned
                JSON resource content should be formatted to be
                more human readable.
            </p>
            <p>
                Default is false.
            </p>
        </td>
    </tr>
</table>


* * *

The contents of this file are subject to the terms of the Common Development and
Distribution License (the License). You may not use this file except in compliance with the
License.

You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
specific language governing permission and limitations under the License.

When distributing Covered Software, include this CDDL Header Notice in each file and include
the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
Header, with the fields enclosed by brackets [] replaced by your own identifying
information: "Portions copyright [year] [name of copyright owner]".

Copyright 2015 ForgeRock AS.
