Paginated Lists in API Responses
Introduction
Compliance data sets get big. A list endpoint that returns every STIG, every organization, or every citation in one response punishes the consumer and the producer alike, so APIs serving GRCSchema data paginate their list responses. This page documents the pagination convention, and how a Thing references a large related collection without embedding it.
A note on history. Earlier versions of this page documented a JSON-LD
PaginatedListtype embedded inside Things. That convention is retired. The pattern below matches what shipping APIs serving GRCSchema data use today.
List endpoints
List endpoints accept two query parameters:
| Parameter | Type | Description |
|---|---|---|
page |
query | Page number (default: 1) |
limit |
query | Items per page (producer sets the default and the maximum) |
The response carries the items under a named key, plus a pagination object describing the window:
{
"organizations": [
{
"@type": "Organization",
"@id": "https://api.example-isv.com/api/v1/organizations/5005",
"elementId": 5005,
"name": "Example Organization"
}
],
"pagination": {
"page": 2,
"limit": 50,
"total": 371,
"totalPages": 8
}
}
Pagination object properties
page: the page this response represents.limit: the number of items per page for this response.total: the total number of items across all pages.totalPages: the number of pages at this limit.
Example request:
# Get the second page, 50 items per page
curl "https://api.example-isv.com/api/v1/organizations?page=2&limit=50"
Referencing large collections from a Thing
A Thing with a one-to-many or many-to-many relationship does not embed the full related list in its response. It references the collection by @id, pointing at the list endpoint where the collection (paginated as above) can be retrieved:
{
"@context": "https://grcschema.org",
"@type": "Account",
"elementId": 1,
"name": "Example Account",
"groups": {
"@id": "https://api.example-isv.com/api/v1/accounts/1/groups",
"itemType": "Group",
"total": 7
}
}
The reference carries the itemType and total so a consumer can decide whether to fetch before paying for the round trip.
The exception. When there's no endpoint to retrieve a related list from, the full list is embedded in the response instead. A short list of
licensesattached to licensed content is the canonical example. The rule of thumb: collections with endpoints get referenced, collections without endpoints get embedded.