HTTP REST API
Contents
Sample resource model
The following examples that follow assumes the following persons model has
been declared in /app/models/persons.json:
{
"fields": {
"firstname": {"type": "string"},
"birthdate": {"type": "date"}
}
}
Enabling HTTP access
The HTTP API has many symmetries to the Model API and allows HTTP REST access to models collections and members with very little coding. The HTTP API is not enabled by default but requires you to provide a resource event handler in the /app/resources directory. In its simplest form, the application resource event handler delegates requests to a ZRM-provided resource event handler.
A resource event handler for the persons model located in
/app/resources/persons.groovy only needs to contain:
ZRM.delegate()
Similarly, if you are using PHP, you will first need to declare a dependency
on zero.php in the /config/ivy.xml file. Now create a
resource event handler for the persons model located in
/app/resources/persons.php which only needs to contain:
<?php zrm_delegate(); ?>
The ZRM resource event handler provides default data access functionality
with HTTP for the data defined in the /app/model file. The remainder of
this section describes that default functionality.
Reading collections
The Model API introduced the concept of a model's collection, Member instances and collection filtering. ZRM's HTTP API maps HTTP requests to invocations on the Model API, providing access to the same collection and member through easy to learn (and construct) URIs.
ZRM follows common REST idioms. Namely, you can use the HTTP GET command for a full or filtered a model's collection and POST member instances into the collection. You can also learn more about Reading and writing model collection member instances.
The HTTP GET URI syntax for addressing model collections is shown in the following example:
<urlPrefix>/<collectionName>[?<queryParameters>]
The following examples are valid URIs for the persons model:
http://localhost/resources/persons
Unfiltered collection of members
http://localhost/resources/persons?firstname__startswith=S
Filtered collection of members where all firstname values start with 'S'
Collection filtering
You can filter collection by limiting the set of members to be returned based on one or more filter conditions. A set of filter parameters is enabled for each collection type based on the data model specified. Some examples were given earlier in this document. Here are some further examples:
http://localhost:8081/resources/persons?firstname__contains=Jo
Filtered collection where member instances' firstname field contains
'Jo'
http://localhost:8081/resources/persons?firstname__contains=Jo&birthdate__day=25,
Filtered collection where member instances' firstname field contains
'Jo' and birthdate falls on the 25th of the any month.
The valid filter conditions and corresponding parameter syntax for the URL is based on the Model API filtering syntax of the Zero Resource Model. This is defined in the Filter conditions section under the Model API topic.
Collection paging
Just as the Model API allows for specifying slice, or subset, of the overall collection, the HTTP API allows you to indicate a page range. This is done by defining the start and count parameters in the URI as follows:
http://localhost/resources/persons?start=100&count=199
Unfiltered collection of members from 101 to 200
http://localhost/resources/persons?firstname__contains=rand&start=5&count=5
Filtered collection of members that contain 'rand' and from 6 to 10
0 and the 10th at 9.
If the data slice specified does not have a complete "page", the returned
members are as expected. For example, if there are 7 members in a given
collection and the first request is for start=0&count=5 then items 1
through 5 are returned. If the second request is made for
start=5&count=5 then items 6 and 7 are returned.
You can optionally specify both start and count. One or both must exist
in order to obtain a slice of the results. The lack of both parameters
means the results is not paged. However, if count is missing, the
results start at the specified start and return up to the end of the
collection. Similarly, if start is missing, the results start at the
beginning of the collection and return the number of members specified by
count.
Collection ordering
As illustrated in the URIs in the previous example, you can order
collections results in your HTTP GET requests. By default, HTTP
collection requests for the Atom representation are sorted by members'
updated value in descending order. Conversely, JSON collection
representations are not sorted, or rather, or sorted from oldest to more
recently created.
The order_by value syntax for the URL is based on the ZRM API syntax
which is defined in the "Model API" section. Ascending order is the
default. To indicated descending order, prefix - before the field name
as show in the previous URI examples:
http://localhost/resources/persons?order_by=birthdate
Unfiltered collection of members sorted youngest to oldest
http://localhost/resources/persons?id__lt=100&order_by=-birthdate,name
Filtered collection of members with id less than 100, sorted first from
oldest to youngest and then by name from A to Z
Collection rendering
At present, collection data can be represented in either JSON or the Atom
syndication format. The desired representation can be specified in the
Accept header of the HTTP GET request by specifying the associated
MIME type. The values application/json and application/atom+xml
render JSON and Atom, respectively, to the response.
An alternative mechanism is provided for requesting a specific
representation by using the URL query parameter format_as. Valid values
for this parameter are json and atom:
http://localhost/resources/persons?format_as=atom
Collection of members with representation returned as Atom.
http://localhost/resources/persons?format_as=json
Collection of members with representation returned as JSON.
The default format is JSON if the Accept header is not specified and the URI parameter is not provided.
JSON representations
ZRM uses a JSON serialization APIs to render the JSON representation. A model collection is a JSON array of objects. Each object contains the member instance of the model in the collection. For example, the persons model when the collection contains two members rendered in JSON is:
[
{
"firstname": "Jane",
"birthdate": "1973-12-03"
},
{
"firstname": "John",
"birthdate": "1982-04-29"
}
]
Atom format
The default Atom representation of a model's collection is as you would
expect: an Atom feed containing an Atom entry for each member. The default
serialization of the model instance member data is put in the
atom:content section as key, value pairs in XOXO format. The remaining
required atom elements are set to default values as shown in the following
example of the default Atom representation of the same data in the JSON
example that was shown above:
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Title of Type persons Feed</title>
<link href="http://localhost/resources/persons?format_as=atom"/>
<updated>2003-12-13T18:30:02Z</updated>
<id>"http://localhost/resources/persons"</id>
<entry>
<title>Title of persons 2</title>
<link href="http://localhost/resources/persons/1?format_as=atom"/>
<link rel="edit" href="http://localhost/resources/persons/1"/>
<id>"http://localhost/resources/persons/1"</id>
<updated>2003-12-13T18:30:02Z</updated>
<author>Author of persons 1</author>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999.xhtml">
<ol class='xoxo'><li>persons<dl>
<dt>firstname</dt><dd>Jane</dd>
<dt>birthdate</dt><dd>1973-12-03</dd>
</dl></li></ol>
</div>
</content>
</entry>
<entry>
<title>Title of persons 2</title>
<link href="http://localhost/resources/persons/2?format_as=atom"/>
<link rel="edit" href="http://localhost/resources/persons/2"/>
<id>"http://localhost/resources/persons/2"</id>
<updated>2003-12-13T18:30:02Z</updated>
<author>Author of persons 2</author>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999.xhtml">
<ol class='xoxo'><li>persons<dl>
<dt>firstname</dt><dd>John</dd>
<dt>birthdate</dt><dd>1982-04-29</dd>
</dl></li></ol>
</div>
</content>
</entry>
</feed>
Customizing the Atom representation
You can use the model declarations in the /app/models folder to
customize the rendering of an Atom entry. You can override named templates
in each model declaration using the calculated_fields definition.
Adding the following definition to the persons model's /app/model/persons.json
file and using the same member instance data in the previous example results in
the following Atom entry:
{
"fields" : { . . . },
"calculated_fields" : {
"atom_author_name": "$member.lastname",
"atom_title": "$member.firstname",
"atom_summary": "All about ${member.firstname}."
},
"calculated_type_fields" : {
"atom_feed_title": "My Custom Feed Title"
}
}
<feed xmlns="http://www.w3.org/2005/Atom">
<title>My Custom Feed Title</title>
<link href="http://localhost/resources/persons?format_as=atom"/>
<updated>2003-12-13T18:30:02Z</updated>
<id>"http://localhost/resources/persons"</id>
<entry>
<title>Jane</title>
<link href="http://localhost/resources/persons/1?format_as=atom"/>
<link rel="edit" href="http://localhost/resources/persons/1"/>
<id>"http://localhost/resources/persons/1"</id>
<summary>All about Jane.</summary>
<updated>2003-12-13T18:30:02Z</updated>
<author>Doe</author>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999.xhtml">
<ol class='xoxo'><li>persons<dl>
<dt>firstname</dt><dd>Jane</dd>
<dt>lastname</dt><dd>Doe</dd>
</dl></li></ol>
</div>
</content>
</entry>
</feed>
Reading and writing collection members
Member rendering and parsing
Incoming data used for creating and updating members must be either in JSON or
Atom representations. The Content-Type header of the HTTP request determines
how the data is parsed. The MIME types application/json and
application/atom+xml parse JSON and Atom, respectively. If neither is
specified, the default parser is JSON.
Creating a member
New collection members can be created by making an HTTP POST request to the
collection URI of the model with the member representation as shown in the
following example:
POST /resources/persons
Content-Type: application/json
{
"firstname": "Bill",
"birthdate": "1976-09-25"
}
Retrieving a member
An individual collection member can be retrieved by issuing an HTTP GET
on the collection URI with the member ID as a parameter, as shown in the
following example:
GET resources/persons/1
Updating a member
A collection member can be updated by issuing an HTTP PUT with the member
representation on the collection URI, as shown in the following example:
PUT /resources/persons/1
Content-Type: application/json
{
"firstname": "Janie",
"birthdate": "1973-12-04"
}
Deleting a member
A collection member can be deleted by issuing an HTTP DELETE with the member
ID on the collection URI, as shown in the following example:
DELETE /resources/persons/1
Reading type collection metadata
By default, the metadata of a collection can be retrieved through HTTP as a JSON representation. This is done using the following URI convention:
/resources/types[/typesId]
For example, assume that the following resource model is defined:
{
"fields" : {
"first_name" : {"type":"string", "required": true},
"birth_date":{"type":"date"},
"is_child":{"type": "boolean"}
}
}
With this model in place, the following HTTP JSON response is returned:
GET /resources/types/persons
{
"type":"person",
"fields": {
"id": {
"type":"auto",
"required":false,
"editable":true,
"primary_key":true
},
"updated": {
"type":"date-time",
"required":false,
"editable":true,
"primary_key":false
},
"birth_date": {
"type":"date",
"required":true,
"editable":true,
"primary_key":false
},
"first_name": {
"type":"string",
"required":true,
"editable":true,
"primary_key":false,
"max_length":50
},
"is_child": {
"type":"boolean",
"required":true,
"editable":true,
"primary_key":false
}
}
}
By specifying the named resource model /resources/types/persons only the JSON
object for the persons type is returned. You can obtain a list of all resource
model definitions by making an HTTP GET request to /resources/types.