µ

µ API

Micro API

Micro API is a subset of JSON-LD intended for representing hypermedia APIs. It includes a vocabulary, and semantics for CRUD operations. As the name implies, it is intended to be concise and generic. Its registered media type is:

Content-Type: application/vnd.micro+json

The current published version is 2017-04-25, and the media type is registered with the IANA.

Introduction #

Micro API simplifies JSON-LD by limiting it to a subset which can be traversed reliably without using processing algorithms. It is designed to look like vanilla JSON and does not assume any prior knowledge of JSON-LD, RDF, OWL, and semantic web in general.

The goal is to reduce these concepts into their most minimal forms possible, and add affordances needed for APIs, such as querying, creating, updating, and deleting resources. It can be considered a hypermedia format, and it conforms to Representational State Transfer (REST) at the highest level.

Example payloads and HTTP requests should be considered non-normative.

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, and OPTIONAL in this specification have the meaning defined in RFC 2119.

Vocabulary #

This section should be considered normative.

Micro API introduces a small vocabulary focused on APIs that is not covered by other standards.

PropertyTypeDescription
idString, NumberA unique value used for identifying resources, most often the primary key in a database.
metaObjectAny meta-information may be contained here.
queryObjectA container for showing information about the current query.
operateObjectReserved for application-specific, arbitrary operations to update resources.
errorObjectIf a request fails for any reason, it MUST return an error in the payload.
isArrayBooleanFor properties, indicates if their values are arrays (this is lacking in RDF). If this is missing, it should be considered false.

Payload Restrictions #

This section should be considered normative.

In general, the payload should look like the flattened form of JSON-LD, with some additional restrictions:

Entry Point #

The expectation of a Micro API entry point is to enumerate types and properties and provide links to collections. It MUST contain the definitions at the top-level, valued as an array of objects, and the type as Ontology.

GET /
{
  "href": "/",
  "type": "Ontology",
  "definitions": [ ... ],
  "Person": { "href": "/people" },
  "Movie": { "href": "/movies" }
}

Definitions communicate the overall schema of the API which is useful for machine clients, and also may include documentation for humans. Here is an example of what they might look like:

[
  { "href": "#name", "id": "name", "label": "Name",
    "propertyOf": [ "#Person", "#Movie" ],
    "propertyType": "xsd:string",
    "type": "Property", "comment": "Given name."
  },
  { "href": "#actor", "id": "actor", "label": "Actors",
    "propertyOf": [ "#Movie" ],
    "propertyType": "#Person", "isArray": true,
    "type": "Property", "comment": "People who acted in a movie."
  },
  { "href": "#Person", "id": "Person", "label": "Person",
    "type": "Class", "comment": "A human being."
  },
  { "href": "#Movie", "id": "Movie", "label": "Movie",
    "type": "Class", "comment": "A moving picture."
  }
]

If the @context is omitted in the payload at the top level, then it must be referenced in a Link header in the response. Important: if done this way, the external @context should be inlined since JSON-LD processors will not dereference it.

{
  "@context": {
    /* Merge this external context:
       http://micro-api.org/context.jsonld */
    "@base": "http://example.com/",
    "@vocab": "http://example.com/#"
  }
}

The @vocab field of a Micro API MUST be the path to the API suffixed with the # character, so that dereferencing always refers to the entry point.

The Link header may be formatted like so:

Link:
  <http://example.com/context.jsonld>;
  rel="http://www.w3.org/ns/json-ld#context";
  type="application/ld+json"

For display purposes, it has been broken into multiple lines, but HTTP headers must always be on one line.

Finding Resources #

A GET request MAY be allowed on the collection IRI for a particular type.

GET /movies
{
  "href": "/movies",
  "graph": [ {
    "type": "Movie",
    "href": "/movies/1",
    "id": 1,
    "name": "The Matrix",
    "actor": {
      "href": "/movies/1/actors",
      "id": [ 1, 2, 3 ]
    }
  } ]
}

Dereferencing a href MUST return types corresponding to that property.

GET /movies/the-matrix/actors?limit=1
{
  "href": "/movies/the-matrix/actors",
  "graph": [ {
    "type": "Person",
    "href": "/people/1",
    "id": 1,
    "name": "Keanu Reeves",
    "reverse": {
      "actor": {
        "href": "/people/1/acted-in",
        "id": [ 1 ]
      }
    }
  } ]
}

It may be OPTIONAL to wrap the resources in a graph if and only if exactly one resource is expected. For example:

GET /people/1
{
  "type": "Person",
  "href": "/people/1",
  "id": 1,
  "name": "Keanu Reeves",
  "reverse": {
    "actor": {
      "href": "/people/1/acted-in",
      "id": [ 1 ]
    }
  }
}

Creating Resources #

Requesting to create an resource MAY be allowed at the collection IRI for that type. The payload MUST be a valid Micro API document, and referenced IDs must be specified using the id property.

POST /people
{
  "graph": [ {
    "name": "John Doe",
    "reverse": {
      "actor": {
        "id": [ "memento" ]
      }
    }
  } ]
}

It may be OPTIONAL to wrap the resource in a graph array if and only if one resource is to be created.

It may be helpful for the response to have a Location header, but it is not required since the response body may include a link to the created resource.

Updating Resources #

IDs MUST be specified in the payload per resource to update, and PATCH requests can be made wherever the resource exists (corollary: IDs can not be changed, only specified).

PATCH /people
{
  "graph": [ {
    "id": "john-doe",
    "name": "Johnny Doe",
    "reverse": {
      "actor": {
        "id": [ "point-break" ]
      }
    },
    "operate": {}
  } ]
}

It may be OPTIONAL to wrap the update in a graph array if and only if one resource is to be updated.

If the a specified resource does not exist at the requested location, it SHOULD return an error. The assumption is that the PATCH method replaces the fields specified. There is a special operate property which allows for arbitrary updates, which this specification is agnostic about. In common update cases, it may be desirable to reject upserts (the PUT method defines that a resource may be created), so PATCH is typically what you want to do.

PATCH requests can update existing resources, however Micro API does not define the semantics to create or delete resources with this method. By setting a link's id property to null (for a to-one relationship) or [] (empty array for a to-many relationship), it removes the link.

Deleting Resources #

DELETE /people/john-doe

A delete request can return no payload (HTTP 204 No Content) if it succeeds. It can apply to any IRI, including collections.

DELETE /people/john-doe/children

In this example, the request means delete all of the resources at this IRI, not just the link.

Error Response #

If a request fails for any reason, it MUST return a error object. The contents of the error object are opaque to this specification.

{
  "error": {
    "label": "NotFoundError",
    "comment": "The requested resource was not found."
  }
}

Querying #

Micro API does not specify anything about pagination, filtering, sparse fields, sorting, etc. For example, the query object MAY contain hints on what queries can be appended to GET requests, with further information about the query provided by a vocabulary (definitions are optional):

{
  "query": {
    "@context": null,
    "include": [],
    "sort": {},
    "field": {},
    "match": {},
    "limit": 1000,
    "offset": 0
  }
}

Unregistered Media Type #

One may use MessagePack instead of JSON as the serialization format for greater bandwidth savings. Since MessagePack is an unregistered media type, the corresponding Micro API media type may be unregistered as well:

Content-Type: application/x-micro-api

It is completely OPTIONAL to support this unregistered media type, but it should be interpreted as Micro API with MessagePack enabled.

Prior Art #

Micro API builds upon JSON-LD, which is a W3C recommendation. A JSON-based serialization format has the advantage of widespread tooling and developer understanding.

In contrast to Linked Data Platform, it does not use the Turtle format, which is useful only for working within RDF. It also lacks a concept of "containers", which assumes that relationships are hierarchical. What is similar is that both stipulate which actions may be taken on resources.

Micro API is an alternative for Hydra, another specification for Web APIs. It is much less prescriptive than Hydra, and is implicit in cases which Hydra is more explicit. For example, some differences are:

A key difference between Micro API and Hydra is that Micro API does not assume that documentation is machine-processable. Why this matters is that natural language may be the only way to express application logic.

About #

The author of this document is Dali Zheng. The source for this document is on GitHub. It is licensed under the CC0 1.0 License.