Collection

A collection resource is a server-managed list of document resources.

Rule: Collection name [col-name]

A plural noun SHOULD be used for collection names, for example 'employers' or 'children'.

Example 1. Collection name

https://api.example.org/demo/v1/employers - a collection of employers

https://api.example.org/demo/v1/employers/{employerId}/subsidiaries - a collection of subsidiaries as a child resource of an employer.

Search

Rule: API operation to search a collection [col-get]

An operation to search a collection resource SHOULD be provided as a GET method on the collection resource URI.

When searching requires input parameters with a complex structure (e.g. extensive filter or sorting parameters), a POST operation on a /search controller MAY be used instead of GET. This allows to represent the input parameters in a structured manner in a JSON request body without the limitations of query parameters. Any pagination input parameters SHOULD still be included as query parameters, allowing to re-send the same payload to retrieve the next page of results.

The recently introduced HTTP method QUERY, providing an alternative to a /search controller, SHOULD NOT be used yet ([meth-http]).

Rule: Representation of a collection [col-repres]

The representation of a collection MUST contain a list of links to child resources:

  • A collection result MUST contain an items property with an array of objects, each one representing an item in the collection.

  • In these objects, a href property MUST be present with a link to the resource.

  • The unique business identifier SHOULD be present for each item.

  • Each item object MAY be extended with some key business properties, needed for display in a master view.

  • In case the collection is empty, the items property MUST have an empty array as value.

  • The title property MAY be used to provide a human-readable description for an item, usable as display text for the link.

  • The number of items in the collection result set MAY be included in the response using the total property. If the response is paginated, its value MUST correspond to the number of items regardless of pagination, rather than only the number of items in the current page.

A collection resource, like other resources, SHOULD always return a JSON object as top-level data structure to support extensibility ([evo-object]). Do not return a JSON array, because the moment you like to add paging, links, etc. your API will break.
Example 2. Consulting a collection
GET https://api.example.org/demo/v1/employers?title=P* HTTP/1.1

Request

GET

/employers/{employerId}

List employers

parameters

sorting, filtering or pagination parameters

Response

body

{
 "items":[
   {
     "href":"https://api.example.org/demo/v1/employers/93017373",
     "title":"Proximus",
     "employerId": 93017373,
     "enterpriseNumber": "0202239951"
   },
   {
     "href":"https://api.example.org/demo/v1/employers/20620259",
     "title":"Partena VZW",
     "employerId": 20620259,
     "enterpriseNumber": "0409536968"
   }
 ],
 "total":2
}

Most used response codes

200

OK

Default response code, also when the collection is empty.

400

Bad Request

Generic error on client side. For example, the syntax of the request is invalid.

404

Not found

The URI provided cannot be mapped to a resource.

204 No content should not be used when consulting a collection.

OpenAPI schemas for the response payload:

EmployersCollection:
  type: object
  properties:
    items:
      type: array
      items:
        $ref: "#/components/schemas/EmployerLink"
    total:
      type: integer
  required:
    - items
    - total
EmployerLink:
  allOf:
  - $ref: common/v1/common-v1.yaml#/components/schemas/HttpLink
  - type: object
    properties:
      employerId:
        $ref: "./employer/identifier/v1/employer-identifier-v1.yaml#/components/schemas/EmployerId"
      enterpriseNumber:
        $ref: "./organization/identifier/v1/organization-identifier-v1.yaml#/components/schemas/EnterpriseNumber"
Example 3. Consultation with complex input structure

If input with a complex structure is needed, a /search controller with POST may be used.

Request
POST https://api.example.org/demo/v1/employers/search
{
  "title": [
    {
      "excludeIfMatching": false,
      "expression": "P*"
    },
    {
      "excludeIfMatching": true,
      "expression": "B*"
    }
  ]
}
Response

The response is the same as for the GET alternative.

Rule: Getting full representations of collection items [col-embed]

When the collection items contain few data, you may want to retrieve them in full when getting the collection. In this case, the full representations MUST be included in an 'embedded' property as described in Embedding resources.

Example 4. Consulting a collection with embedded items
GET https://api.example.org/demo/v1/appendices/employerclasses?embed=items HTTP/1.1​
Response
{
 "items": [
  {
   "value": "0",
   "href": "https://api.example.org/demo/v1/appendices/employerclasses/0"
  }, {
   "value": "2",
   "href": "https://api.example.org/demo/v1/appendices/employerclasses/2"
  }
 ],
 "total":2,
 "embedded": {
   "https://api.example.org/demo/v1/appendices/employerclasses/2": {
     "value": "2",
     "description": {
       "nl": "Bijzondere categorie voor werkgevers die voor hun arbeiders een speciale bijdrage verschuldigd zijn.",
       "fr": "Catégorie particulière pour les employeurs redevables pour les ouvriers d'une cotisation spéciale."
      }
   },
   "https://api.example.org/demo/v1/appendices/employerclasses/0": {
     "value": "0",
     "description": {
      "nl": "Algemene categorie voor werkgevers van commerciële of niet-commerciële aard.",
      "fr": "Catégorie générale pour les employeurs, de type commercial ou non-commercial."
     }
   }
 }
}
JSON schemas
AppendixCodesCollection:
  description: A collection of appendix codes
  type: object
  properties:
    items:
      type: array
      items:
        $ref: '#/components/schemas/AppendixCodeLink'
    total:
      type: integer
    embedded:
      type: object
      additionalProperties:
        $ref: 'appendixCode.yaml#/components/schemas/AppendixCode'
  required:
    - items
    - total
AppendixCodeLink:
  allOf:
  - $ref: 'common/v1/common-v1.yaml#/components/schemas/HttpLink'
  - type: object
    properties:
      value:
        $ref: 'appendixCode.yaml#/components/schemas/AppendixCodeValue'

Sorting

Rule: Sorting a collection [col-sort]

A sort multi-value query parameter MAY be provided to allow a client to sort the items of a collection resource on one or more specified properties. Descending sorting order can be indicated by prefixing the property name with -.

The API SHOULD document which properties can be used for sorting, and whether descending order is allowed.

In case a /search controller is used, the sorting parameters should be represented in a structured manner in the request body, instead of using query parameters. Separate parameters for sorting properties and sorting order can be used then.

Table 1. Sort query parameter

sort

Multi-value query param with list of properties to sort on. Direction is ascending by default. To indicate descending, prefix property with -.

?sort=age&sort=-name

Filtering

Rule: Filtering items in a collection [col-filter]

A collection may support query parameters to filter its items:

  • a query parameter with the name of a document property, filters items on the specified value

  • the query parameter q is reserved for a full text search on all the document’s content

  • other filter parameters may be supported, e.g. to look up items within a search period

Unless the API documentation explicitly states otherwise, returned collection items:

  • should satisfy ALL filter query parameters (AND-logic)

  • have to match ANY of the values of a multi-valued filter query parameter (OR-logic).

For example, the query GET /cars?doors=5&color=black&color=blue should be interpreted by default as: "search for all cars that have 5 doors AND are of color blue OR black".

Example 5. Searching in a collection
GET https://api.example.org/demo/v1/enterprises?title=P* HTTP/1.1

GET

/organizations

get all the organization documents in the collection

Parameters

name

query-param

Only match organizations that have a specific name.

Response

body

{
  "items": [
    {
      "href": "https://api.example.org/demo/v1/organizations/0202239951",
      "name": "Proximus",
      "enterpriseNumber": "0202239951"
    },
    {
      "href": "https://api.example.org/demo/v1/organizations/0816851945",
      "name": "Partena",
      "enterpriseNumber": "0816851945"
    }
  ],
  "total": 2
}

Most used response codes

200

OK

Default response code, also when filtered collection is empty.

400

Bad Request

Generic error on client side. For example, the syntax of the request is invalid.

404

Not found

The URI provided cannot be mapped to a resource.

204 No content should not be used with GET.

Pagination

Rule: Paging over a large collection [col-paging]

Collection with too many items MUST support pagination. There are two pagination techniques:

  • offset-based pagination: numeric offset identifies a page

  • cursor-based (aka key-based or luke index): a unique key element identifies a page

Cursor-based pagination has some advantages, especially for high volumes. Take into account the considerations listed in the Zalando API guidelines before choosing a pagination technique.

Table 2. Reserved JSON properties for pagination
next MANDATORY (except for the last page) hyperlink to the next page

next

REQUIRED (except for the last page)

hyperlink to the next page

prev

OPTIONAL

hyperlink to the previous page

pageSize

RECOMMENDED

Maximum number of items per page. For the last page, its value should be independent of the number of actually returned items.

page

REQUIRED (offset-based); N/A (cursor-based)

index of the current page of items, should be 1-based (the default and first page is 1)

first

OPTIONAL

hyperlink to the first page

last

OPTIONAL

hyperlink to the last page

total

OPTIONAL

Total number of items across all pages. If filter parameters are used, this is the total of the result set after filtering, not of the entire collection.

The names of the properties with hyperlink values and the items property are derived from the IANA registered link relations.

Table 3. Reserved query parameters for pagination

pageSize

OPTIONAL

maximum number of items per page desired by client; must have a default value if absent.

page

REQUIRED with default value 1 (offset-based); N/A (cursor-based)

the index of page to be retrieved

A reusable PageQueryParameter OpenAPI component is defined in common-v1.yaml. Examples of other OpenAPI components for pagination can be found here, but should be modified according to which pagination parameters, size limits and default values are supported by your API.

Example 6. Offset-based pagination
GET https://api.example.org/demo/v1/organizations?page=2&pageSize=2 HTTP/1.1
{
  "items": [
    {
      "href": "https://api.example.org/demo/v1/organizations/0202239951",
      "title": "Proximus",
      "enterpriseNumber": "0202239951"
    },
    {
      "href": "https://api.example.org/demo/v1/organizations/0212165526",
      "title": "CPAS de Silly",
      "enterpriseNumber": "0212165526"
    }
  ],
  "pageSize": 2,
  "page": 2,
  "total": 7,
  "first": "https://api.example.org/demo/v1/organizations?pageSize=2",
  "last": "https://api.example.org/demo/v1/organizations?page=4&pageSize=2",
  "prev": "https://api.example.org/demo/v1/organizations?page=1&pageSize=2",
  "next": "https://api.example.org/demo/v1/organizations?page=3&pageSize=2"
}
Example 7. Cursor-based pagination
GET https://api.example.org/demo/v1/organizations?after=0244640631 HTTP/1.1
{
  "items": [
    {
      "href": "https://api.example.org/demo/v1/organizations/0202239951",
      "title": "Proximus"
    },
    {
      "href": "https://api.example.org/demo/v1/organizations/0212165526",
      "title": "CPAS de Silly"
    }
  ],
  "pageSize": 2,
  "total": 7,
  "first": "https://api.example.org/demo/v1/organizations?pageSize=2",
  "next": "https://api.example.org/demo/v1/organizations?after=0212165526&pageSize=2"
}

Create a new resource

The collection resource can be used to create new document resources from the POST request body. Absent optional values are set to their default value if one is specified in the OpenAPI description.

POST

/employers

create a new employer in the collection

Request

body

The data of the resource to create.

{
  "name": "Proximus",
  "employerId": 93017373,
  "enterprise": {
    "enterpriseNumber": "0202239951"
  }
}

Response headers

Location

http-header

The URI of the newly created resource e.g. /employers/93017373

Response

body

The API should specify for each creation operation, if it returns:

  • an empty body,

  • a partial resource representation (e.g. only a generated resource identifier),

  • or a full resource representation.

Most used response codes

201

Created

Default response code if the resource is created.

409

Conflict

The resource could not be created because the request is in conflict with data on the server. E.g. the resource already exists (duplicate key violation).

303

See Other

The resource already exists. May be returned instead of 409 Conflict if it is considered a normal use case to perform the operation for an already existing resource. The Location header refers to the resource.

​200 OK should not be used with POST for creating resources.
POST /employers HTTP/1.1

HTTP/1.1 201 Created
Location: /employers/93017373
Content-Length: 0
Date: Wed, 06 Jan 2016 15:37:16 GMT

Remove

A selection of items can be removed from a collection using the DELETE method. In fact, the collection itself cannot be removed, but it can be emptied if all its items are removed. By using query parameters, the items to be removed can be filtered. In order to remove a single specific item from a collection, use DELETE on the document resource.

DELETE

/employers

Delete all the employers documents in the collection.

Parameters

name

query-param

Remove only employers that have a specific name.

Response

body

Empty or a message indicating success.

Most used response codes

200

OK

The items are successfully removed from the collection and returned.

204

No content

The items are successfully removed from the collection but no additional content is included in the response body.

400

Bad Request

Generic error on client side. For example, the syntax of the request is invalid.

404

Not found

The collection resource does not exist and thus cannot be deleted.