Ga naar hoofdinhoud

Resources

Introduction

The API of a data layer is centered around resources. A resource represents a 'thing' of a certain type that may be identified by a globally unique URI. It can correspond to anything — from a physical object (e.g. a building or a person) to an abstract concept (e.g. a collection or a type of art work).

Resource types

This specification defines the following high-level resource types:

NameDescription
Root CollectionAn ordered list of collections.
CollectionAn ordered list of objects. A collection may be a part of a root collection. A collection may consist of pages, containing sublists of the collection.
PageAn ordered sublist of objects within a collection.
ObjectAn object of any kind.

The resource types are extensible. This specification defines, for example, an Entity Collection and an Entity Page, specialized versions of the generic Collection and Page, respectively. Similarly, the API of a data layer may define its own resource types, extending the existing ones.

notitie

To do: rename 'Root Collection' to e.g. 'Collection Series' (per DCAT - 'Dataset Series'). The current name is a bit technical and could suggest that it's always at the top.

The following entity-relationship diagram visualizes the relationships between the resource types:

notitie

To be discussed: replace the ER diagram with a class diagram to make the relationships clearer (e.g. inheritance).

notitie

To do: rephrase this section. According to Activity Streams an object is the primary base type, but this section suggests an object is more or less an entity.

Object structure

An Object resource contains at least the following top-level fields:

NameData typeCardinalityDescription
idstring0 or 1The identifier of the object, if known. It MUST be a URI. Optional for volatile, non-persistent objects.
typestring1The type of the object. This specification defines a number of high-level types and extensions. The API may additionally define its own types, especially entity types.
namestring0 or 1The name of the object, if known and relevant to the object.

Example of the response body:

{
"id": "https://example.org/v1/entities/objects/1234",
"type": "HeritageObject",
"name": "The Night Watch",
// And then, depending on the resource, other fields, such as:
"additionalTypes": [
{
"id": "https://example.org/v1/entities/concepts/5678",
"type": "Concept",
"name": "Painting"
}
],
"description": "Rembrandt’s largest, most famous canvas was made for the Arquebusiers guild hall..."
}

The response indicates that this object has identifier https://example.org/v1/entities/objects/1234, is a 'Heritage object' and has name 'The Night Watch'.

Note the additionalTypes field for exposing specific information about the nature of the object. Every item in this list is also an object and has the same top-level fields: id, type and name.

Root Collection structure

A Root Collection resource contains at least the following fields:

NameData typeCardinalityDescription
idstring1The identifier of the collection. It MUST be a URI.
typestring1The type of the collection. It MUST be of type RootCollection or a specialization.
namestring1The name of the collection.
totalItemsnumber0 or 1The total number of collections in the collection.
itemsarray1A list of all collections in the collection. It MUST be of type RootCollection or Collection or a specialization.
partOfRootCollection0 or 1The root collection of which this collection is a part. Not set if this collection is the top-level root collection.
partOf.idstring1The identifier of the root collection.
partOf.typestring1The type of the root collection. It MUST be of type RootCollection or a specialization.

Example

Example of the response body:

{
"id": "https://example.org/v1/entities",
"type": "RootEntityCollection",
"name": "Entities",
"totalItems": 2,
"items": [
{
"id": "https://example.org/v1/entities/objects",
"type": "EntityCollection",
"name": "Heritage objects"
},
{
"id": "https://example.org/v1/entities/persons",
"type": "EntityCollection",
"name": "Persons"
}
]
}

Collection structure

A Collection resource contains at least the following fields:

NameData typeCardinalityDescription
idstring1The identifier of the collection. It MUST be a URI.
typestring1The type of the collection. This specification defines specific types, e.g. EntityCollection. The API may additionally define its own types.
namestring1The name of the collection.
totalItemsnumber0 or 1The total number of resources in the collection. This MAY be an estimate, especially in case of a large collection. The field MAY be omitted by the API if the total number is too costly to calculate.
itemsarray0 or 1A list of resources in the collection. A resource can be of any type. Not set if the resources are parts of pages.
firstPage0 or 1The first page in the collection. Not set if the collection is empty.
first.idstring1The identifier of the first page in the collection.
first.typestring1The type of the first page in the collection. This specification defines specific types, e.g. EntityPage. The API may additionally define its own types.
lastPage0 or 1The last page in the collection. Not set if the collection is empty or the last page is unknown (e.g. in case of cursor pagination).
last.idstring1The identifier of the last page in the collection.
last.typestring1The type of the last page in the collection. This specification defines specific types, e.g. EntityPage. The API may additionally define its own types .
partOfRootCollection1The root collection of which this collection is a part.
partOf.idstring1The identifier of the root collection.
partOf.typestring1The type of the root collection. It MUST be of type RootCollection or a specialization.

Example

Example of the response body when a collection embeds its items directly:

{
"id": "https://example.org/v1/collections/objects/extensions/suggestions/keywords?q=mil",
"type": "KeywordSuggestionCollection",
"name": "Keyword suggestions",
"totalItems": 2,
"items": [
{
"type": "SuggestionTerm",
"relevance": 98,
"value": {
"type": "KeywordSuggestion",
"name": "mill"
}
},
{
"type": "SuggestionTerm",
"relevance": 92,
"value": {
"type": "KeywordSuggestion",
"name": "windmill"
}
}
],
"partOf": {
"id": "https://example.org/v1/collections/objects/extensions/suggestions",
"type": "RootSuggestionCollection"
}
}

The response indicates that this collection consists of 2 items, and that these items can be accessed directly via items.

Example of the response body when the collection is divided into pages:

{
"id": "https://example.org/v1/entities/objects",
"type": "EntityCollection",
"name": "Heritage objects",
"totalItems": 195,
"first": {
"id": "https://example.org/v1/entities/objects?page=1",
"type": "EntityPage"
},
"partOf": {
"id": "https://example.org/v1/entities",
"type": "RootEntityCollection"
}
}

The response indicates that this collection consists of 195 items, and that these items can be accessed via a first page.

Page structure

A Page resource contains at least the following fields:

NameData typeCardinalityDescription
idstring1The identifier of the page. It MUST be a URI.
typestring1The type of the page. This specification defines specific types, e.g. EntityPage. The API may additionally define its own types.
namestring1The name of the page.
itemsarray1A list of resources in the page. Empty if there are no resources. A resource can be of any type.
prevPage0 or 1The previous page in the collection. Not set if there is no previous page.
prev.idstring1The identifier of the previous page in the collection.
prev.typestring1The type of the previous page in the collection. This specification defines specific types, e.g. EntityPage. The API may additionally define its own types.
nextPage0 or 1The next page in the collection. Not set if there is no next page.
next.idstring1The identifier of the next page in the collection.
next.typestring1The type of the next page in the collection. This specification defines specific types, e.g. EntityPage. The API may additionally define its own types.
partOfCollection1The collection of which this page is a part. All fields of a collection MUST be embedded. See the Collection structure.

Pagination

notitie

To do:

  • Explain how pagination between pages works.
  • Explain the choice between page and cursor navigation.

Example

Example of the response body:

{
"id": "https://example.org/v1/entities/objects?page=3",
"type": "EntityPage",
"name": "Heritage objects",
"items": [
{
"id": "https://example.org/v1/entities/objects/1234",
"type": "HeritageObject",
"name": "The Night Watch"
// Other fields...
}
// Other items...
],
"prev": {
"id": "https://example.org/v1/entities/objects?page=2",
"type": "EntityPage"
},
"next": {
"id": "https://example.org/v1/entities/objects?page=4",
"type": "EntityPage"
},
"partOf": {
"id": "https://example.org/v1/entities/objects",
"type": "EntityCollection",
"name": "Heritage objects",
"totalItems": 195,
"first": {
"id": "https://example.org/v1/entities/objects?page=1",
"type": "EntityPage"
},
"last": {
"id": "https://example.org/v1/entities/objects?page=20",
"type": "EntityPage"
}
}
}

The response indicates that this page contains items, is related to a previous page and a next page and is a part of a collection.

Resource identification with URIs

notitie

To do: explain how resources must be identified with URIs:

  • See the general requirements of the REST API Design Rules, e.g. plural names (/entities, not /entity), lower case names (/entities, not /Entities), dashes (/heritage-objects, not /heritageObjects), slashes to denote hierarchy (/entities/persons, not /entities-persons);
  • Use camel case in query parameters (?filterBy=dateCreated, not ?filter-by=date-created);
  • Individual resources must have deterministic IDs if they come from publication systems of data providers;
  • URIs must still be treated as if they were opaque strings ("the URI patterns are to facilitate developers understanding the API, not to facilitate software to interact with it").