REST-based APIs - A Template for Services
This document is currently in the process of being replaced by Common Services REST API documentation.
This document provides suggested templates for REST-based APIs, for potential adoption by many of the services in CollectionSpace's services layer. This implements part of the work described in the "REST Service Contracts" section of Web Services - Paradigms and Contracts.
Some generic message payloads and envelopes that are to be used with the proposed APIs below, such as the message payloads to be returned in a response when an error occurs, are detailed in Common System Specific Elements.
REST-based APIs, and their associated client-visible resource models, are suggested below for the three major types of CollectionSpace services: entity services, relation (association) services, and task services:
REST-based APIs for Entity Services
Search rough, in-process notes
REST-based APIs for Relation (Association) Services
REST-based APIs for Task Services
REST-based APIs for Entity Services
Service Discovery
Description
Purpose
Retrieves a human-readable description of the service. This also verifies that the service exists, without interacting with the resources that it provides.
Request
GET /{resources_as_a_plural_noun}/description
Request: Entity Body
The body of this request SHOULD be empty. If it is non-empty, the body will be ignored.
Response: Status Codes
Code | Meaning | Returned When |
|---|---|---|
200 | OK | The description of the service was returned successfully. |
404 | Not Found | The resource at /{resources_as_a_plural_noun}/description does not exist. |
500 | Internal Server Error | A service error prevented the resource from begin returned. |
Response: Content-Type
text/plain (for plain text)
multipart/mixed (for generic XML content)
See Questions or Issues, below.
Response: Entity Body (on Success)
Returns a human-readable description of the service: in plain text, in an XML format, or both, TBA. See Questions or Issues, below.
Response: Entity Body (on Error)
Returns an XML document containing a description of the error. See Common System Specific Elements for details.
As RESTful Service - Ajax Patterns notes, "Error responses should ... be in human-friendly language and with examples and hyperlinks."
Questions or Issues
We need to decide if this description is made available in plain text, in a particular XML format, or both. If both, the default format can be retrieved using the pattern above, and specific formats can be retrieved by adding filename extensions; e.g.:
/{resources_as_a_plural_noun}/description.txt (for a plain text description)
/{resources_as_a_plural_noun}/description.xml (for an XML-based description)
Schema
Purpose
Retrieves the schema for the XML-based message payload that is exchanged in several of this service's operations.
Instance documents conforming to this schema may be exchanged in a variety of contexts. For instance, they may be:
Sent by a client in the body of a request, to perform a Create operation.
Sent by a client in the body of a request, to perform an Update operation.
Returned by the service in a response, when a specific object (entity) is requested.
Returned by the service in a response, when a list of objects (entities) is requested, in a format that returns full object records, (rather than just hyperlinks, or just hyperlinks accompanied by abbreviated object records).
Request
GET /{resources_as_a_plural_noun}/schema
There will be only one schema returned per resource. If there may be typed resources, or child resources, available anywhere within the URL path, schemas for these resources can be retrieved via variations on this generic pattern, as in this example:
GET /{resources_as_a_plural_noun}/{typed_or_child_resources_as_a_plural_noun}/schema
Request: Entity Body
The body of this request SHOULD be empty. If it is non-empty, the body will be ignored.
Response: Status Codes
Code | Meaning | Returned When |
|---|---|---|
200 | OK | The schema was returned successfully. |
404 | Not Found | The resource at /{resources_as_a_plural_noun}/schema does not exist. |
500 | Internal Server Error | A service error prevented the resource from being returned. |
Response: Content-Type
application/xml (for schemas expressed in XML-based schema languages)
Response: Entity Body (on Success)
Returns the schema for the XML-based message payload that is exchanged in several of this service's operations.
By default, the schema will be declared in the W3C XML Schema language.
Response: Entity Body (on Error)
Returns an XML document containing a description of the error. See Common System Specific Elements for details.
Questions or Issues
If there may be a requirement to return schemas in additional schema languages, such as RELAX NG, the default format can be retrieved using the pattern above, and specific formats can be retrieved by adding filename extensions; e.g.
/{resources_as_a_plural_noun}/schema.xsd (for a W3C XML Schema document)
/{resources_as_a_plural_noun}/schema.rng (for a RELAX NG schema document)
CRUD Operations (Create, Read, Update, Delete)
Create
Purpose
Creates a new resource of the specified type.
Request
POST /{resources_as_a_plural_noun}
The RESTful metaphor is that of creating a new instance of the resource within a container of, or bucket of, resources of this type.
If there may be typed resources, or child resources, available anywhere within the URL path, new resources of that type can be created via variations on this generic pattern, as in this example:
POST /{resources_as_a_plural_noun}/{typed_or_child_resources_as_a_plural_noun}
Request: Entity Body
If the service allows the client to supply the resource to be created:
The body of this request MUST contain a valid instance of an XML document, conforming to the schema used by the service.
If the service generates an instance of the resource algorithmically:
The body of this request SHOULD be empty. If it is non-empty, the body will be ignored.
Response: Status Codes
Code | Meaning | Returned When |
|---|---|---|
400 | Bad Request | The resource could not be created because the data sent in the entity body of the request was bad, as determined by the service. |
401 | Unauthorized | The resource could not be created because the client submitting the request either has not provided authentication credentials, or authentication failed (e.g. due to an invalid username or password) after such credentials were provided. |
403 | Forbidden | The resource could not be created because the client submitting the request was not authorized to create new resources in this container. |
409 | Conflict | The resource could not be created because the submitted data would create a duplicate (non-unique) resource, as determined by the service. |
500 | Internal Server Error | A service error prevented the resource from being created. |
Response: Content-Type
application/xml
Response: Location
Returns the URL for the newly-created object.
Response: Entity Body (on Success)
Returns a representation of the newly-created resource, as an XML document conforming to the schema used by the service.
Returns an empty entity body.
Response: Entity Body (on Error)
Returns an XML document containing a description of the error. See Common System Specific Elements for details.
Questions or Issues
We need to decide when a POST of a new resource to a container or bucket results in a 409 Conflict error. One example may be when the value of an information unit (aka field or data element) in the POSTed resource conflicts with a value of that same information unit in an existing resource. This might occur, for instance, in the case of a RDBMS column (field) on which there is a PRIMARY KEY or UNIQUE constraint.
Read
Purpose
Reads (aka retrieves or returns) a representation of a specific instance of this resource.
Request
GET /{resources_as_a_plural_noun}/{resource_identifier}
The {resource_identifier} is a value that uniquely identifies a particular resource. It may be an ID or some other type of identifier.
If there may be typed resources, or child resources, available anywhere within the URL path, these resources can be retrieved via variations on this generic pattern, as in this example:
GET /{resources_as_a_plural_noun}/{typed_or_child_resources_as_a_plural_noun}/{resource_identifier}
Request: Entity Body
The body of this request SHOULD be empty. If it is non-empty, the body will be ignored.
Response: Status Codes
Code | Meaning | Returned When |
|---|---|---|
200 | OK | A representation of the resource was read (i.e. returned) successfully. |
401 | Unauthorized | The resource could not be read because the client submitting the request either has not provided authentication credentials, or authentication failed (e.g. due to an invalid username or password) after such credentials were provided. |
403 | Forbidden | The resource could not be read because the client submitting the request was not authorized to read it. |
404 | Not Found | The resource at /{resources_as_a_plural_noun}/{resource_identifier} does not exist. |
500 | Internal Server Error | A service error prevented the resource from being read. |
Response: Content-Type
multipart/mixed
Response: Entity Body (on Success)
Returns a representation of the requested resource, as one or more documents conforming to the schema used by the service.
Consists of one or more MIME message parts, each separated by a message-specific boundary line, and each part containing a separate document. Each of these parts of the message is currently of Content-Type: application/xml.
The MIME message part whose label ends in _common contains a document conforming to the "common" schema for a particular entity; that is, the schema that will be present for all tenants in a specific deployment. The "common" schema is also supported by search and other functionality which does not apply to extension schema. If there are other MIME message parts present, ending in a name other than _common, these parts will typically represent one or more extension schema, specific to the current tenant.
An example, showing two MIME message parts, each containing XML documents representing part of a CollectionObject: one containing the fields in an extension schema (collectionobject_naturalhistory), and the second containing the fields in the common schema (collectionobjects_common).
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 2.4; JBoss-4.2.3.GA (build: SVNTag=JBoss_4_2_3_GA
date=200807181439)/JBossWeb-2.0
Content-Type: multipart/mixed;
boundary=ab8d331a-9720-45c9-a629-2c71050f1720
Content-Length: 1643
Date: Wed, 02 Dec 2009 23:18:13 GMT
--ab8d331a-9720-45c9-a629-2c71050f1720
label: collectionobjects_naturalhistory
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<ns2:collectionobjects_naturalhistory
xmlns:ns2="http://collectionspace.org/services/collectionobject/domain/naturalhistory"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://collectionspace.org/services/collectionobject/domain/naturalhistory
http://collectionspace.org/services/collectionobject/domain/collectionobjects_naturalhistory.xsd">
<nh-string>test-string</nh-string>
<nh-int>999</nh-int>
<nh-long>9999</nh-long>
</ns2:collectionobjects_naturalhistory>
--ab8d331a-9720-45c9-a629-2c71050f1720
label: collectionobjects_common
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<ns2:collectionobjects_common
xmlns:ns2="http://collectionspace.org/services/collectionobject"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://collectionspace.org/services/collectionobject
http://services.collectionspace.org/collectionobject/collectionobjects_common.xsd">
<otherNumbers>
<otherNumber>urn:org.collectionspace.id:24082390</otherNumber>
<otherNumber>urn:org.walkerart.id:123</otherNumber>
</otherNumbers>
<objectNumber>updated-objectNumber-1259718776712</objectNumber>
<briefDescription>Papier mache bird mask with horns, painted red with black
and yellow spots. Puerto Rico. ca. 8&quot; high, 6&quot; wide,
projects 10&quot; (with horns).</briefDescription>
<objectName>updated-objectName-1259718776712</objectName>
</ns2:collectionobjects_common>
--ab8d331a-9720-45c9-a629-2c71050f1720--
Response: Entity Body (on Error)
Returns an XML document containing a description of the error. See Common System Specific Elements for details.
Read (Multiple)
Purpose
Reads (aka retrieves or returns) a list of 0 to n instances of this resource.
Depending on the query parameters submitted, the list may include either:
0 to n hyperlinks, each accompanied by the minimum information required to identify, in a human-readable manner, their linked-to resources.
Hyperlinks are fully-qualified (i.e. not relative) URLs that may subsequently be used to retrieve any of the individual records in the list, via the Read operation, above.
Hyperlinks are accompanied by human-readable information, which provides a brief preview of what may be expected to be retrieved by following those links. This information is typically obtained from one or more of the information units (aka fields or data elements) in each record, and may represent an abbreviation, combination or adaptation of that information. The content of this human-readable identification is service-specific.
or
0 to n full records for matching resources.
The default behavior is to return hyperlinks, each accompanied by the minimum information required to identify, in a human-readable format, their linked-to resources.
Request
GET /{resources_as_a_plural_noun}
GET /{resources_as_a_plural_noun}?{optional_query_parameters ...}
If there may be typed resources, or child resources, available anywhere within the URL path, these resources can be retrieved via variations on this generic pattern, as in these examples:
GET /{resources_as_a_plural_noun}/{resource_identifier}/{typed_or_child_resources_as_a_plural_noun}
GET /{resources_as_a_plural_noun}/{resource_identifier}/
{typed_or_child_resources_as_a_plural_noun}?{optional_query_parameters ...}
A highly recommended child resource, for read (multiple) operations, will return a count of the numbers of records to be returned, as in this example:
GET /{resources_as_a_plural_noun}/count
GET /{resources_as_a_plural_noun}/count?{optional_query_parameters ...}
Query parameters
This section poses some hypothetical query parameters for initial discussion. The following examples are somewhat crude placeholders:
Some possible examples of query parameters to modify read (multiple) requests. These in part come from Common System Specific Elements:
?orderby={information_unit}
Requests that hyperlinks or full records be returned in the natural sort order of a particular information unit (field or data element). Defaults to ascending order if the sortorder query parameter isn't present.
sortorder={ascending|descending}
Specifies the sort order. Ignored if the orderby query parameter isn't also present.
?groupby={}
Specifies grouping of results. (Additional details TBA.)
?pagesize={nn} (or maxrecords=nn, etc.)
Return results with a maximum of nn items (hyperlinks or full records) returned per query.
?format={hyperlinks|full_records}
Requests that either hyperlinks or full records be returned. Defaults to hyperlinks.
Note that these query parameters may be combined; e.g. ?orderBy={information_unit}&pageSize={nn}
Request: Entity Body
The body of this request SHOULD be empty. If it is non-empty, the body will be ignored.
Response: Status Codes
Code | Meaning | Returned When |
|---|---|---|
200 | OK | A list of the resources was returned successfully. |
400 | Bad Request | There was an error in the query parameters submitted with the request. |
403 | Forbidden | A list of resources could not be returned because the client submitting the request was not authorized to read that list. |
404 | Not Found | The resource at /{resources_as_a_plural_noun} does not exist. |
500 | Internal Server Error | A service error prevented the list of resources from being read. |
Response: Content-Type
application/xml
Response: Entity Body (on Success)
Returns a list of representations of the requested resources, as an XML document conforming to the schema used by the service.
Response: Entity Body (on Error)
Returns an XML document containing a description of the error. See Common System Specific Elements for details.
Questions or Issues
We need to decide on XML-based representations for returning lists of entities:
With hyperlinks and abbreviated identification
With full records
We need to fully discuss the types of query parameters required.
We need to fully discuss how paging of the results returned (via a query parameter like pagesize or maxrecords), in responses from CollectionSpace service, will work. One way of facilitating this might be to return, in an envelope or preface in the entity body, values indicating a) the total number of records retrieved, b) the start position (index) of the first record in the current result set, and c) the numbers of records returned in that set. Note that this is not currently expected to use HTTP's Chunked Transfer Encoding mechanism. Rather, each response is expected to be a complete HTTP message, with some indication (such as the envelope or preface mentioned above) that the results returned constitute a subset of the total records available.
Update
Purpose
Completely updates in place (i.e. replaces) an existing resource of the specified type.
Request
PUT /{resources_as_a_plural_noun}/{resource_identifier}
The {resource_identifier} is a value that uniquely identifies a particular resource. It may be an ID or some other type of identifier.
If there may be typed resources, or child resources, available anywhere within the URL path, resources of that type can be updated via variations on this generic pattern, as in this example:
PUT /{resources_as_a_plural_noun}/{typed_or_child_resources_as_a_plural_noun}/{resource_identifier}
Request: Entity Body
The body of this request MUST contain a valid instance of an XML document, conforming to the schema used by the service.
Response: Status Codes
Code | Meaning | Returned When |
|---|---|---|
200 | OK | A new instance of the resource was updated successfully at /{resources_as_a_plural_noun}/{resource_identifier}. |
400 | Bad Request | The resource could not be updated because the data sent in the entity body of the request was bad, as determined by the service. |
401 | Unauthorized | The resource could not be updated because the client submitting the request either has not provided authentication credentials, or authentication failed (e.g. due to an invalid username or password) after such credentials were provided. |
403 | Forbidden | The resource could not be updated because the client submitting the request was not authorized to update resources in this container. |
404 | Not Found | The resource at /{resources_as_a_plural_noun}/{resource_identifier} does not exist. |
500 | Internal Server Error | A service error prevented the resource from being updated. |
Response: Content-Type
application/xml
Response: Entity Body (on Success)
Returns a representation of the updated resource, as an XML document conforming to the schema used by the service.
Response: Entity Body (on Error)
Returns an XML document containing a description of the error. See Common System Specific Elements for details.
Questions or Issues
There doesn't appear to be well-defined support in the REST architecture for partial (sparse) updates of a resource, equivalent to the UPDATE table_name SET column=value statement in SQL. Some discussion:
Two of several mechanisms through which we might facilitate partial (sparse) updates, noting that these mechanisms are not currently suggested here as patterns, include:
Providing direct access to any interesting information units (fields or data elements) via URL-addressable resources; e.g. /{resources_as_a_plural_noun}/{resource_identifier}/{information_unit_name}, and then using PUT to completely update the contents of any of these individual information units.
POSTing (as opposed to PUTting) a partial update to the resource at /{resources_as_a_plural_noun}/{resource_identifier}. This sidesteps the lack of support for partial (sparse) updates in REST, since the semantics of POST are entirely up to the application. The payload sent in the body of the update request might consist of form data in the 'application/x-www-form-urlencoded' content-type, or might potentially be in an XML format (TBA). There may well need to be some distinction, in any partial (sparse) update submitted in those or similar formats, between fields that are simply to be ignored - not processed - in the update request, and fields whose values are to be removed (made empty, or blank).
Delete
Purpose
Deletes a specific instance of this resource.
Request
DELETE /{resources_as_a_plural_noun}/{resource_identifier}
The {resource_identifier} is a value that uniquely identifies a particular resource. It may be an ID or some other type of identifier.
If there may be typed resources, or child resources, available anywhere within the URL path, resources of that type can be deleted via variations on this generic pattern, as in this example:
DELETE /{resources_as_a_plural_noun}/{typed_or_child_resources_as_a_plural_noun}/{resource_identifier}
Request: Entity Body
The body of this request SHOULD be empty. If it is non-empty, the body will be ignored.
Response: Status Codes
Code | Meaning | Returned When |
|---|---|---|
200 | OK | The resource was successfully deleted. |
401 | Unauthorized | The resource could not be deleted because the client submitting the request either has not provided authentication credentials, or authentication failed (e.g. due to an invalid username or password) after such credentials were provided. |
403 | Forbidden | The resource could not be deleted because the client submitting the request was not authorized to delete it. |
404 | Not Found | The resource at /{resources_as_a_plural_noun}/{resource_identifier} does not exist. |
500 | Internal Server Error | A service error prevented the resource from being deleted. |
Response: Content-Type
application/xml
Response: Entity Body (on Success)
Returns a representation of the just-deleted resource, as an XML document conforming to the schema used by the service.
If the deletion occurred in error, or an 'undo' operation is desired, the client can use this representation to once again create the resource.
Response: Entity Body (on Error)
Returns an XML document containing a description of the error. See Common System Specific Elements for details.
Search
This section is an in-process placeholder. The notes below are very rough at present.
Approaches to Search
As RESTful Service - Ajax Patterns notes:
... REST will always have different interpretations. The ambiguity is exacerbated by the fact that there aren't nearly enough HTTP methods to support common operations. The most common example is the lack of a search method, meaning that different people will design search in different ways.
The two most widely used approaches to REST-based search that we have observed to date involve a) submitting a request containing query parameters, via GET and b) constructing and submitting a structure, via POST. Some variations on these approaches, both observed and hypothesized, include:
Accepting GET requests with a single query parameter. (That query parameter may often be named 'q=', 'query=', or 'search='.)