API for HTTP Access to the Cantus Database

This is the Application Programming Interface for Cantus database-access projects. The 1.x versions will only allow searching and reading the database, though (pending funding) 2.x versions will add the ability to create and edit resources.

To navigate the specification, use the brief Table of Contents to the right, or the Detailed Table of Contents below.

Description

The API’s basic design works thusly:

  • a resource’s URL “pathname” identifies a resource uniquely
  • the HTTP method indicates the action to perform; you may wish to GET a resource, receive a list of the available OPTIONS for a resource, or SEARCH for resources that meet certain criteria.
  • the HTTP headers indicate a desired data format (in requests) and actual format plus metadata (in responses).
  • when present, request and response bodies are normally in JSON, although the default may later change to XML.

Why an API for Cantus?

This section answers several related questions about why we would bother to specify and write out an API for Cantus. The quick answer is that we wanted to allow long-term interoperability and stability across Cantus-related software.

Intentionally writing an API encourages wise design, rather than a haphazard compilation of functionality. Having a known specification allows developers, both within Cantus and those working for third parties, to easily know how to use the Cantus database server. Preparing an implementation- independent API allows us to change any part of the server’s implementation without affecting user agents and third-party software. Offering an HTTP API allows writing new user interfaces, whether for Web browsers or mobile devices, by only writing new user interface code (whereas replacing a Drupal-generated user interface requires replacing Drupal’s database management code).

The API was developed as part of an effort to replace an existing, Drupal-based database. The developers wanted to allow easier interoperability with the “Cantus Ultimus” project produced by a third party, and to develop two user interfaces (one for Web browsers, one for tablet computers), all using the same server software.

There are undoubtedly additional benefits, and some disadvantages.

A Note about URLs

Throughout this document, URLs are usually indicated in a generic format, to emphasize the unimportance of the specific URL. For this reason, domain names are usually omitted so that URLs begin with /. In addition, most URLs contain parenthesized parts, as in /(browse.chant)/, to indicate that server implmentations may change actual URLs arbitrarily, so clients must determine all URLs dynamically at runtime by consulting the "resources" member of response bodies.

For this reason, servers MUST provide clients with relevant URLs in known locations as indicated throughout the API. In general, there are three actions to expect for every resource type:

  • browse: to access a sortable, paginated list of all resources of a given type.
  • view: to access a specific
  • search: to browse filter resources by certain criteria

Requests to the root URL (i.e., / as in https://abbott.cantusproject.org/) will enumerate the URLs in the following way:

HTTP/1.1 200 OK
Location: (server_address)/

{
    "resources":
        {
            "browse": {
                "chant": "/chants",
                "feast": "/browse/others/feasts/"
                },
            "view": {
                "chant": "/view/chant/id?",
                "feast": "/view/id?/feast/"
                }
        }
}

As you can see, the URLs provided in this example response body are highly irregular, and represent poor design desicions on the part of the server implementor. Yet because the URLs are provided in a consistent manner, Cantus user agents may still navigate the database with relative ease. The URL to use when viewing a specific chant, for instance, will always be available from the ['resources']['view']['chant'] member in the response body for the server’s root URL.

There are a few other points to note:

  • URLs to related resources will always be held in the "resources" member of a response body, for every resources, throughout the Cantus API.
  • In the "resources" member, resource types are always in the singular form.
  • “View” URLs will contain the string id?, which should be replaced with the “id” of the resource the user agent wishes to access.
  • Search queries use the “browse” URL with the SEARCH method; browse queries use the GET method.

Root URL JSON Specification

GET /

Fetch JSON object with URLs and URL patterns to access database records. All URLs are transmitted as strings. The URL patterns have 'id?' in the string, which must be replaced with the id of a specific resource. All other URLs should be used wihtout modification.

Response JSON Object:
 
  • resources (object) – URLs and URL patterns to database resources.
  • resources.browse (object) – URLs to retrieve all resources of a type (with a GET request) or only resources that match some criteria (with a SEARCH request).
  • resources.browse.all (URL) – URL to browse/search resources of every type.
  • resources.browse.chant (URL) – URL for Chants.
  • resources.browse.source (URL) – URL for Sources.
  • resources.browse.indexer (URL) – URL for Indexers.
  • resources.browse.feast (URL) – URL for Feasts.
  • resources.browse.genre (URL) – URL for Genres.
  • resources.browse.century (URL) – URL for Centuries.
  • resources.browse.notation (URL) – URL for Notations.
  • resources.browse.office (URL) – URL for an Offices.
  • resources.browse.portfolio (URL) – URL for Portfolio Categories (portfolia).
  • resources.browse.provenance (URL) – URL for Provenances.
  • resources.browse.siglum (URL) – URL for RISM Siglums (sigla).
  • resources.browse.segment (URL) – URL for Database Segments.
  • resources.browse.status (URL) – URL for Source Statuses.
  • resources.view (object) – URL patterns to retrieve single resources with a known “id.”
  • resources.view.chant (URL) – Pattern for a Chant.
  • resources.view.source (URL) – Pattern for a Source.
  • resources.view.indexer (URL) – Pattern for a Indexer.
  • resources.view.feast (URL) – Pattern for a Feast.
  • resources.view.genre (URL) – Pattern for a Genre.
  • resources.view.century (URL) – Pattern for a Century.
  • resources.view.notation (URL) – Pattern for a Notation.
  • resources.view.office (URL) – Pattern for an Office.
  • resources.view.portfolio (URL) – Pattern for a Portfolio Category.
  • resources.view.provenance (URL) – Pattern for a Provenance.
  • resources.view.siglum (URL) – Pattern for a RISM Siglum.
  • resources.view.segment (URL) – Pattern for a Database Segment.
  • resources.view.status (URL) – Pattern for a Source Status.

Find Server Version

The fastest and safest way to ensure a user agent and server use compliant versions of the Cantus API is to use a HEAD or OPTIONS request on the root URL.

HEAD /

Find the API version supported on the server.

Response Headers:
 
  • X-Cantus-Version – Indicates the Cantus API version implemented by a client or server. Values are described in API Versions and Version Numbers.
  • Server – Indicates the implementation and its version. This SHOULD NOT be used by the user agent to modify behaviour, but it MAY be of interest for debugging or other purposes. The reference implementation is called “Abbot.”

Relationship to Existing Standards

The Cantus API implements parts of the HTTP/1.1bis standard (IETF RFCs 7230, 7231, 7232, 7234, and 7237).

This document supplements the IETF memoranda to describe what functionality is to be implemented in Cantus software, and what behaviour to expect. In particular, the Cantus API defines application-specific headers, content formatting, and a search specification.

Keywords indicating technical requirements are used as per RFC 2119.

High-Level Overview and Examples

At a high level, knowing how to format a request is primarily an issue of choosing the right URL path, the right HTTP method, and the right HTTP headers. Parsing the response is about knowing the expected members in the JSON-formatted response body.

Beacuse this API is designed with the “REST” principles in mind, every session of interaction begins with a GET request to the root URL, written in this documentation as /. The response body indicates the URL path to use in constructing URLs of various resource types. An abbreviated sample interaction goes like this.

Request:

GET / HTTP/1.1

Response:

HTTP/1.1 200 OK

{
    "resources": {
        "browse": {
            "source": "/sources/",
            "feast": "/feasts/",
            "chant": "/chants/",
        ...
    }
}

From which you have learned the means by which to make the URLs to sources, feasts, and chants. Whenever possible, metadata about the results is held in the HTTP headers, since this allows clients to use easier formatting-for-display algorithms, and also to make use of the HEAD HTTP method in many situations.

In this example request, the client requests the HTTP headers corresponding to a search query for the “Chant” resources that contain “dixit dominus”:

HEAD https://(browse_chants)/357685/ HTTP/1.1
If-None-Match "7827ff38cb8ef147d9f5edb749a0f300dac2ebe1"

Consider the following response:

HTTP/1.1 304 Not Modified
ETag "7827ff38cb8ef147d9f5edb749a0f300dac2ebe1"
Server "Abbott/1.0"
X-Cantus-Fields: feast differentia position genre source sequence office fest_desc cantus_id id mode full_text incipit folio

With this (abbreviated) header information the client can make an informed decision about how to proceed. The If-None-Match and ETag headers tell us that this chant’s content has not changed since the last time the client checked, so transmitting the response body would have been redundant anyway. With the X-Cantus-Fields header we also know the fields the database has for this chant—and more importantly that some of the fields are mising (like marginalia and volpiano).

API Versions and Version Numbers

To help ensure easier interoperability and compatibility of clients and servers, the Cantus API will use “semantic versioning.” This results in three-part version numbers separated by a period, like 1.0.0 and 4.6.3, though note that the periods are not decimals, so numbers like 4.14.4 are possible.

  • The leftmost number is the “major version,” and it must be incremented whenever a backward-incompatible change is introduced, which should be rarely. Thus clients and servers that implemenet different major versions are simply incompatible.
  • The middle number is the “minor version,” and it must be incremented whenever a new feature is introduced. Thus clients and servers that implement different minor versions are compatible if only using the features of the lower minor version.
  • The rightmost number is the “point release,” and it must be incremented whenever an error is fixed (since this API is not software and cannot technically fail to implement itself, this will mostly consist of clarifications and spelling or grammatical corrections).

Note that this applies after the 1.0.0 version. 0.x.x versions are intended for API development, so arbitrary changes may happen arbitrarily.

Indices and tables