Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lws10-core/container-representation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ A container representation MUST include the following properties:
- **`id`**: The URI of the container.
- **`type`**: The value `"Container"`.
- **`totalItems`**: An integer indicating the total number of resources contained in the container.
- **`items`**: An array of contained resource descriptions (see below). If the container is empty, this MUST be an empty array.
- **`items`**: An array of contained resource descriptions (see below). If the container is empty,
this MUST be an empty array. When the container listing is paginated, `items` contains only the
current page of resources; see [Pagination](#pagination) for details.

#### Contained Resource Description

Expand Down
5 changes: 5 additions & 0 deletions lws10-core/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ <h2>Container Representation</h2>
<div data-include="container-representation.md" data-include-format="markdown" data-include-replace="true"></div>
</section>

<section id="pagination">
<h2>Pagination</h2>
<div data-include="pagination.md" data-include-format="markdown" data-include-replace="true"></div>
</section>

<section id="operations">
<h2>Operations</h2>
<div data-include="operations.md" data-include-format="markdown" data-include-replace="true"></div>
Expand Down
123 changes: 123 additions & 0 deletions lws10-core/pagination.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
### Pagination

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion to remove specific references to containers.

Containers may hold a large number of resources. To allow clients to retrieve container
listings incrementally, servers MUST support pagination for containers whose membership

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This text is a bit ambiguous: the server MUST support pagination, but the server is allowed to determine for itself that the threshold is Infinity. So, for more clarity, in my opinion, either there MUST always be pagination (independent of server-determined thresholds), or there SHOULD be pagination (allowing a server to pick and choose for itself which containers contain pagination or not)

@elf-pavlik elf-pavlik Mar 23, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I left or at least 👍 similar comment on the prior google doc

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just moving from MUST to SHOULD and minor edits should be fine

Containers may hold a large number of resources. To allow clients to retrieve container listings incrementally, servers SHOULD support pagination (e.g., for containers whose membership exceeds a server-determined threshold).

exceeds a server-determined threshold.

#### Pagination Model

Pagination is link-based: the server provides pagination URIs via HTTP `Link` headers [[!RFC8288]],
allowing clients to navigate the full listing without relying on numeric offsets. The server
determines page boundaries and page size.

When a container listing is paginated, the response body contains only the current page of items. The
container's `id`, `type`, and `totalItems` properties reflect the full container, while `items`
contains only the resources on the current page.

#### Pagination Link Relations

Pagination URIs are conveyed in `Link` headers using the following standard link relations:

- **`rel="first"`**: The URI of the first page of results. MUST be present on paginated responses.
- **`rel="last"`**: The URI of the last page of results. MAY be present on paginated responses.
- **`rel="next"`**: The URI of the next page of results. MUST be present when there are subsequent
pages. MUST be omitted on the last page.
- **`rel="prev"`**: The URI of the previous page of results. MAY be present when there are preceding
pages. MUST be omitted on the first page.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm -1 on requiring prev and last. Those may be significantly hard to compute depending on the pagination strategy of the server.

I'm OK with merging this PR and reflecting this comment in an issue to solve later on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one of the things handled by proper implementation of something like ODBC's Scrollable Cursors, as I suggested elsewhere. prev and last only need to be computed when the client has requested they be available and when the server supports them.


All pagination URIs are opaque to the client. Clients MUST NOT construct or modify pagination
URIs; they MUST use the URIs provided by the server.

#### Requesting Pages

A client requests the container URI to obtain the first page. The response includes pagination
Link headers that the client follows to retrieve subsequent pages. Servers MAY also support
direct access to specific pages via the pagination URIs obtained during a previous scan.

When a paginated response is returned, the server MUST respond with 200 OK. The `totalItems`
property in the response body MUST reflect the total number of items across all pages, not just the
current page.

#### Example: Paginated Container

Request:
```
GET /alice/photos/ HTTP/1.1
Authorization: Bearer <token>
Accept: application/lws+json
```

Response (first page):
```
HTTP/1.1 200 OK
Content-Type: application/lws+json
ETag: "photos-page1-etag"
Link: </alice/photos/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: </alice/photos/.acl>; rel="acl"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
Link: </alice/photos/?page=1>; rel="first"
Link: </alice/photos/?page=3>; rel="last"
Link: </alice/photos/?page=2>; rel="next"

{
"@context": "https://www.w3.org/ns/lws/v1",
"id": "/alice/photos/",
"type": "Container",
"totalItems": 150,
"items": [
{
"type": "DataResource",
"id": "/alice/photos/vacation.jpg",
"mediaType": "image/jpeg",
"size": 248392,
"modified": "2025-11-20T10:30:00Z"
},
{
"type": "DataResource",
"id": "/alice/photos/portrait.png",
"mediaType": "image/png",
"size": 102400,
"modified": "2025-11-21T14:15:00Z"
}
]
}
```

Request (next page):
```
GET /alice/photos/?page=2 HTTP/1.1
Authorization: Bearer <token>
Accept: application/lws+json
```

Response (middle page):
```
HTTP/1.1 200 OK
Content-Type: application/lws+json
ETag: "photos-page2-etag"
Link: </alice/photos/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: </alice/photos/.acl>; rel="acl"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
Link: </alice/photos/?page=1>; rel="first"
Link: </alice/photos/?page=1>; rel="prev"
Link: </alice/photos/?page=3>; rel="next"
Link: </alice/photos/?page=3>; rel="last"

{
"@context": "https://www.w3.org/ns/lws/v1",
"id": "/alice/photos/",
"type": "Container",
"totalItems": 150,
"items": [
{
"type": "DataResource",
"id": "/alice/photos/sunset.jpg",
"mediaType": "image/jpeg",
"size": 315000,
"modified": "2025-11-22T09:00:00Z"
}
]
}
```