API Documentation of the Flask app

The interactive documentation of the REST api with Redoc can be found here: Api documentation

The OpenAPI specification can also be downloaded here: api.json

Format of API Responses

The API is a REST API that should be navigatable by only using links. The default (and only) response document format of the API is JSON. To accommodate for the fact that JSON does not have a native link datatype a custom format is used for all API responses.

Warning

This format is currently a draft only and may change anytime!

Example of the custom format:

{
    "links": [
        {
            "href": "/api/v1/auth/",
            "rel": ["api", "authentication"],
            "resourceType": "api"
        },
        {
            "href": "/api/v1/auth/login/",
            "rel": ["login", "post"],
            "resourceType": "login"
        },
        {
            "href": "/api/v1/namespaces/",
            "rel": ["namespace", "collection", "page", "page-1"],
            "resourceType":"namespace",
            "key": {"?item-count": "10", "?sort": "name"}
        }
    ],
    "embedded": [
        {
            "links": [],
            "data": {
                "self": {
                    "href": "/api/v1/namespaces/nsExample/",
                    "rel": ["namespace"],
                    "resourceType": "namespace",
                    "key": {"namespaceId": "nsExample"},
                    "schema": "url-to-json-schema",
                    "doc": "url-to-human-documentation",
                    "name": "Example Namespace"
                }
            }
        }
    ],
    "keyedLinks": [
        {
            "href": "/api/v1/namespaces/",
            "rel": ["namespace", "collection", "page"],
            "resourceType":"namespace",
            "queryKey": ["item-count", "cursor", "sort"]
        },
        {
            "href": "/api/v1/namespaces/{namespaceId}/",
            "rel": ["namespace"],
            "resourceType":"namespace",
            "key": ["namespaceId"]
        }
    ],
    "data": {
        "self": {
            "href": "/api/v1/",
            "rel": ["api", "root"],
            "resourceType": "api"
        }
    }
}

Each API response always has the two fields links and data. An api response may have the field keyedLinks or teh field key, or both. Additionally a top level (not embedded) API response can have the embedded field.

links

Contains all navigational links relevant for the current resource. The rel attribute of a link is a list of strings. This allows for a more fine grained tagging of the links than a single rel value could. The type of the resource found behind the link is also expressed as a rel value. For example "api" is a collection of REST resources that form an API.

The client should use these links for navigating the Api. The client should only select the links based on their rel attributes and must not depend on a specific url in the href attribute!

embedded

Contains API response objects that are related to the returned API response. These can be cached by the client to avoid subsequent api calls.

The client must never depend on anything returned inside of the embedded attribute!

keyedLinks

Contains shortcut links that contain a template url that can be used with a key to construct a valid url. The links in this list contain a key attribute that matches the template variables in the url and can be used to check if the key is compatible with this link. Additionally a keyed link can also specify a queryKey attribute with all accepted query variable names for this endpoint. If the queryKey attribute is set the key attribute can be omitted and is treated as an empty json object.

The client should only use these links when there is no alternative navigation possible using only normal links from the links attribute. This can be the case if the client stored the resource key in the url and has to reconstruct its state from its current url (or similar). The client must check if the key matches the key attribute of the keyed link before constructing the link.

key

A minimal key for this resource that can be used with a keyed link. The key is a mapping from key variables to key values (both as strings).

The self link of any API response mus be reachable by relations only from the api root or specify a key. The same applies for any link in the links attribute of a api response.

A key can contain query variables that must begin with a ? character (that is stripped away). These query variables must be matched against the queryKey attribute of a keyed link.

To construct a link from a keyed link all keys of the link’s key attribute must have a value in the key. Then the key values can be safely used to fill in the the template variables that correspond to the key variables (the keys of the key mapping). All query variables supported by the keyed link must be appended to the query part of the url with the value they have in the key.

If a key has more key variables than specified in the links key attribute it must still create a valid url to an existing resource. This resource may not be of the same type as the resource the key was from.

If the key has exactly all key variables (query variables do not count for this) specified in the links key attribute the resource found behind the url must be the same resource the key was from. If the key has query variables then additionally all query variables must be supported by the keyed link for the key to match the keyed link exactly.

The meaning of key variables should be as stable as the meaning of a rel attribute (never change them without updating the api major version!). To introduce a new key format change the key variable names or add a versioned variable name to the key for matching. Not all key variables must be used in the url template of a keyed link.

data

Contains a single data object.

All data objects have a self attribute that contains their canonical url. This attribute should be used to discover the links for the specific object if it is part of a collection resource.

If the resource is a collection data contains a an object of the form {"self": {...}, "items": []}. The items attribute of the collection contains a list of links to the resources in the collection. The actual resources should always be provided in the embedded attribute of the API response. If a client does not use the embedded attribute to populate a client side cache it can replace the links in the items attribute with the corresponding embedded item by matching the href of the link and the items self link.

A client that caches API responses may use the url in the self attribute of the data object as the cache key for this API response if the response contains exactly one object.

All links are represented by a json object with a href and a rel attribute. The href attribute should contain a fully realized url without any variables. The rel attribute should contain a rel for the type of the resource. If the resource behind the url should be called with another http method the method should be included as a rel (in lowercase). The resourceType attribute of the link is the type of resource the API will will deliver when calling this link. The resourceType is also one of the entries in rel. The schema attribute should contain a valid (and stable) url to a json schema describing the returned (or expected) object (only the data part of an API response). The doc attribute should contain a valid (and stable) url to the documentation for this resource. This attribute is intended for humans exploring the api. The name attribute is the display name of the link. A client can show this name to the a human user.

Rationale Behind the Format

The format is similar to (and inspired by) the existing json format standards, that standardise how links should be embedded into json documents. It does however not follow any one specific format. This is because the exisiting formats are often very verbose (json+LD) or otherwise have serious limitations in their expressiveness or ease of use.

The custom format should enable the following goals:

Navigate the API without constructing URLs

To reach the highest level of maturity of a REST API (HATEOAS) it is neccessary to be able to navigate the API by only following the provided hyperlinks. The format should allow the specification of these links with enough detail to allow navigation and actions on resources (e.g. crud actions using http methods). This means that the link format must have a way to specify what http/crud methods are supported by this resource.

Specify how to navigate with templated links

The format should allow to define shortcuts to resources with templated urls. This is necessery if the client does not want to encode the full self link of a resource into its state url. The format should allow clients to reliably and safely decide what state needs to be encoded into the clients state url and how this state can be used later with the templated urls.

Seperate metadata from the data

The metadata (e.g. the links and embedded responses) should be easy to seperate from the data. The format should make it easy to work with the data without all the extra api information embedded into the data object.

Allow for caching and embedding responses

The embedded objects should be cacheable as is with the chache api provided by modern browsers. The client should only need to reconstruct a response object with the embedded response as the response body based on the current response headers.

Usable without supporting library

The format should be usable (and ideally provide additional benefits over plain json objects) without a full library that handles parsing and caching in the client. The navigational portion of the format (navigating the api via the provided links) should follow simple rules while still allowing clients to benefit from the additional metadata provided (like schema or type information). Caching should be made as simple as possible for the client.

Avoid special characters for attribute names

Because most formats mix the data with their annotations they use special characters to differentiate their attributes from the data’s attributes. This makes using the json objects more cumbersome as for example in javascript accessing these fields cannot be done with the dot notation.

The custom format is mostly inspired by the JSON+Hal specification. The JSON+Hal format is very easy to use with only three special defined attributes (_links, _embedded and self (in the _links attribute)). This makes it easy to learn. In fact all three attributes can be found again in the custom format.

Note

Inspirations for the custom format:

JSON+Hal

Link: https://tools.ietf.org/html/draft-kelly-json-hal-06

Inspired the naming of the links, embedded and self attributes (but without the undescores).

Ion

Link: https://ionspec.org

Inspired the rel attribute of links to be a list instead of a single string. Also inspired me to encode http methods into links.

The data attribute is inspired by the value attribute of value objects.

Collection+JSON

Link: http://amundsen.com/media-types/collection/

Inspired a single list of links rather than using the map style of JSON+Hal or from Ion.

SIREN

Link:

Inspired a single list of links rather than using the map style of JSON+Hal or from Ion. Inspired encapsulating the object in a data attribute (SIREN uses properties).

Relevant articles and other links:

The actual data object is encapsuled in the data attribute. This was done specifically, to make it trivially easy to seperate the data from the metadata of the response like links and other embedded objects. The only restriction this format poses on the data object is that it has a self attribute JSON+Hal actually embeds everything into the actual data object with the special attributes. This means that to work with a clean data object one must first remove the links and embedded objects (without removing the special self link).

The embedded field contains full API responses (only the json response body). These can easily be used to fill a cache to prevent execcive requests to the backend. Only single resources should be embedded. A embedded API response must have an empty array for its embedded field!

The links are contained in a single uniform array. This allows for easier parsing of all links. For example JSON+Hal could have a list of links or a single link for each key. The _links attribute of a JSON+Hal object is a map where the keys are the rel for the link(s) behind the keys. This makes finding a link by a single rel easier, but also makes it impossible to specify multiple values for rel. For example in a paginated resource the “next” link can not have the type of its resources in the rel as “next” is already set. The same goes for the special rel “self”.

The custom format adresses this shortcoming by having multiple rels inside the link object itself. The type of the REST resource can also be specified with the special resourceType attribute of the link. By having multiple rels we can also encode crud actions and http methods for the links.

Consider the following example:

[
    {"href": "/api/objects/", "rel": ["collection", "myobject"], "resourceType": "myobject", "schema": "link-to-GET-myobject-schema"},
    {"href": "/api/objects/", "rel": ["create", "post", "myobject"], "resourceType": "myobject", "schema": "link-to-POST-myobject-schema"}
]

Here we can see that by having multiple rel values we can encode, that the same url can be used to get the collection of all myobjects and to create a new myobject with the POST method. By specifying a list of special rel values the client can utilise this information and know even before calling the link what type of resource is returned and if it is a collection of these resources.

By providing a schema url in the link object we can provide the client with a machine readable description of the object returned when visiting that link. The client can use this schema to dynamically generate a view (or input form) for this object type. For links that specify the http method to be used (and where the method is not GET) the schema refers to the required input expected from the client.