Skip to content

Introducing support for Containers in the LWS protocol#81

Merged
laurensdeb merged 23 commits into
mainfrom
containers-base
Mar 2, 2026
Merged

Introducing support for Containers in the LWS protocol#81
laurensdeb merged 23 commits into
mainfrom
containers-base

Conversation

@laurensdeb

@laurensdeb laurensdeb commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

This PR continues on the discussions of the proposed mechanics for containers in LWS.

Changes from the initial discussions

  • Split out the pagination and multiple containment proposals.
  • Introduce new Media Type (resolves LWS Container Media Type #61)
  • Update terminology section
  • Merge certain changes proposed in comments on Google docs

Context

It is part of a series of three PRs:


Preview | Diff

Introduce the container model from the LWS Containers proposal with
single containment semantics. Add new sections for container
representation, container media type, and JSON-LD context/vocabulary.
Update terminology across operations: partOf→up, contains→items,
@id→id, @type→type, flatten item properties, adopt new media type
(application/ld+json; profile="https://www.w3.org/ns/lws/v1"), and
use Link header rel="type" for container creation instead of
Content-Type-based type detection.
Add definitions for container, data resource, root container, and
containment to the terminology section.
Define application/lws+json as the default media type for container
representations, equivalent to application/ld+json with the LWS
profile. Servers must return the same payload for application/lws+json,
application/ld+json, and application/json — only the Content-Type
header varies. Update IANA considerations with profile parameter,
security considerations, and equivalence note following the Activity
Streams precedent.
@laurensdeb laurensdeb marked this pull request as draft February 23, 2026 12:31
Comment thread lws10-core/logicalresourceorganization.md
A container representation MUST include identifiers for all contained
resources when the client has read access. Authorization-based filtering
is not required; it is noted as an optional consideration with caveats
about performance and caching. Sub-containers with appropriate access
controls are suggested as an alternative.

New resources are created using POST to a target container URI, with the server assigning the final identifier. Clients MAY suggest a name via the Slug header. Clients MAY provide initial user-managed metadata for the new resource by including one or more Link headers in the POST request, following the syntax of Web Linking in [[RFC8288]]. Server-managed metadata MUST be generated automatically by the server upon creation and MUST NOT be overridden by client-provided links.
On success, return the 201 status code with the new URI in the Location header. The server MUST include Link headers for key server-managed metadata, such as a link to the parent container (rel="partOf"), a link to the ACL resource (rel="acl"), and a link to its dedicated linkset resource (rel="linkset"; type="application/linkset+json"). Additional links SHOULD include rel="type" (indicating Container or DataResource) and rel="mediaType" if applicable. The body MAY be empty or include a minimal representation of the resource. All metadata creation and linking MUST be atomic with the resource creation to maintain consistency.
New resources are created using POST to a target container URI, with the server assigning the final identifier. Clients MAY suggest a name via the `Slug` header. Clients MAY provide initial user-managed metadata for the new resource by including one or more `Link` headers in the POST request, following the syntax of Web Linking in [[RFC8288]]. Server-managed metadata MUST be generated automatically by the server upon creation and MUST NOT be overridden by client-provided links.

This comment was marked as resolved.

This comment was marked as resolved.

On success, return the 201 status code with the new URI in the Location header. The server MUST include Link headers for key server-managed metadata, such as a link to the parent container (rel="partOf"), a link to the ACL resource (rel="acl"), and a link to its dedicated linkset resource (rel="linkset"; type="application/linkset+json"). Additional links SHOULD include rel="type" (indicating Container or DataResource) and rel="mediaType" if applicable. The body MAY be empty or include a minimal representation of the resource. All metadata creation and linking MUST be atomic with the resource creation to maintain consistency.
New resources are created using POST to a target container URI, with the server assigning the final identifier. Clients MAY suggest a name via the `Slug` header. Clients MAY provide initial user-managed metadata for the new resource by including one or more `Link` headers in the POST request, following the syntax of Web Linking in [[RFC8288]]. Server-managed metadata MUST be generated automatically by the server upon creation and MUST NOT be overridden by client-provided links.

On success, return the 201 status code with the new URI in the `Location` header. The server MUST include `Link` headers for key server-managed metadata, such as a link to the parent container (`rel="up"`), a link to the ACL resource (`rel="acl"`), and a link to its dedicated linkset resource (`rel="linkset"; type="application/linkset+json"`). Additional links SHOULD include `rel="type"` (indicating `Container` or `DataResource`). The body MAY be empty or include a minimal representation of the resource. All metadata creation and linking MUST be atomic with the resource creation to maintain consistency.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACL wording is probably old copy-paste things

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I suggest to not state "Container or DataResource" but instead "https://www.w3.org/ns/lws#Container or https://www.w3.org/ns/lws#DataResource"

@w3cbot

w3cbot commented Feb 23, 2026

Copy link
Copy Markdown

This was discussed during the #lws meeting on 23 February 2026.

View the transcript

w3c/lws-protocol#81

laurens: more details about 81
… some parts were spuriously removed, I will fix that after this meeting
… this PR describes the notion of root container, and focuses on single containment
… the wording might be too strict in some places, we might want to make it more lenient to allow multiple containment in *some* implementations
… note the extension of the terminology section
… it describes integrity of the containment, clarifies the deletion logic
… note that the parent container of a resource is no longer announced with rel="partof" , but wuth rel="up"
… not permission-based filtering on containers
… but a note describes how to do it

bendm: the phrasing is quite strict right now

laurens: correct; there was a lot of discussions about the original proposal being to flexible
… I'm hoping to merge it as is, but of course the PR is open for discussion

bendm: there is a MUST at some place, then a note says "MAY chose not to"
… are we describing the minimum requirements, or a maximum?

laurens: typically, for spec text we would describe the minimum requirements
… there are different ways of approaching this; I'm not particularly bound to the approach I took
… there is no systematic approach in the spec right now, on how to describe those options

<Zakim> acoburn, you wanted to ask about stictness and extensibility

acoburn: to echo what bendm was saying,
… we need to be careful about any restriction that we have.
… We want to support interoperability, which we get by being prescriptive.
… But we also want to allow future spefifications to build upon ours.
… Anything we forbid could be hindering that.
… If we restrict containment to be single-containment, we forbid multiple-containment in future extensions.

laurens: PR 81 supports only single containment. PR 83 softens it and adds the option to have multiple-containment.

acoburn: great; woudl be good to comment that in the PR.

pchampin: +1 on being prescriptive but also to echo Ben's concern
… what I see in section 7.5, there is a MUST and in the note a "MAY not respect the MUST"
… not saying this is wrong, but not a fan of adding requirements and then adding exceptions
… notes are non-normative, so they should not contain normative language

<TallTed> If that NOTE is retained, such MUSTs SHOULD be changed to SHOULD.

laurens: this is some more work needed on this section

laurens: moving on to the section on Container Representation
… some clarifications on the description of the format, but a lot of changes
… I would like the opinion of the group on the "mediaType" attribute of contained resources
… should we have a single value or an array?

acoburn: I don't have a strong opinion on this
… but bengo pointed out some time ago that we are describing a resource here, while mediaType is a property of a representation

laurens: I think we can modify that subsequently, once we have some implementation experience
… moving on to Operations
… introduce some wording (also in the IANA considerations) about content-negotiation of application/lws+json as application/ld+json or application/json
… application/lws+json SHOULD be considered equivalent to ld+json with profile; maybe we want a MUST there

pchampin: +1 about conneg: one should be able to get JSON or JSON-LD, not sure it should be part of IANA considerations

laurens: this is not in the IANA section, rather it is in the MediaType section
… minor editorial tweaks in the rest of the Operations section
… also the previously mention changed on rel=up replacing rel=partOf
… the section describing Creation of resources describes how to create an empty container
… in the example for creating a DataResource, I added Link relation types in the response
… also added an example of creating a container
… In the section about deleting resources, I added some working about deleting empty container resources and non-empty container resources.
… There are some proposals about requesting a recursive deletions, not sure they should make its way into the spec as is.

laurens: it would be good is everyone could review this PR and comment on it

<pchampin> s/subrobpic/subtopic/g

<Zakim> acoburn, you wanted to ask about recursive delete

acoburn: related to recursion; in my experience at Inrupt, there is a UX issue here.
… or maybe rather Developer Experience
… it is very handy to be able to do that
… we could reuse what exists in WebDAV
… I would prefer that, if possible, than reinventing something new


Use POST to add a new resource inside an existing container. The server assigns an identifier to the resource, optionally suggested via the `Slug` header. The server MAY honor the Slug header if it does not conflict with naming rules or existing resources. Clients indicate the type of resource to create as follows:

- To create a **Container**, the client MUST include a `Link` header with `rel="type"` pointing to the Container type: `Link: <https://www.w3.org/ns/lws#Container>; rel="type"`.
- To create a **DataResource**, the client includes the resource content in the request body with the appropriate `Content-Type` header.

This comment was marked as resolved.

@TallTed TallTed Feb 27, 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.

This is one of those things that the user will want to do in one step ("{put|copy|mov} this folder and all its contents there"), which the software may need to do in several (create a container named xyz at location bcd, and put each of these documents inside it; and (for a move) after all that has succeeded, delete the originals).

Several pieces of ACID consideration come into play. We should NOT try to reinvent specifications for all these processes and activities, but learn from the wheels that already exist, and re-implement the things that have been previously specified.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Agree. How do you suggest we proceed?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

(I just saw next comment about #87 , we can continue there 👌 )

In this example, the client is posting to the container `/alice/notes/`. It provides `text/plain` content (a grocery list) and suggests the name `shoppinglist.txt` for the new resource. If `/alice/notes/` exists and the client is authorized, the server will create a new DataResource and add it to the container's membership.

**Example (Response to POST):**
**Example (Response to POST — data resource):**

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I suggest to consistently use the same term and capitalization (for easier searching in the spec doc). So maybe consistently use "Data Resource" (two words, title caps), so we can also differentiate our search with the rel-type URI?

Content-Length: 0
```
On success, return 201 Created with the new URI in the Location header. The body may be empty or a minimal representation. Include relevant headers such as Content-Type matching the created resource; Content-Length: 0 indicates no body. Server responses MUST use entity tags for responses that contain resource representations or successful responses to HEAD requests, enabling concurrency control in subsequent operations.
On success, return 201 Created with the new URI in the `Location` header. The body may be empty or a minimal representation. Server responses MUST use entity tags for responses that contain resource representations or successful responses to HEAD requests, enabling concurrency control in subsequent operations.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should we consistently write return statements as MUSTs for the server?

On success, the server MUST return 201 Created [...]

```
On success, return 201 Created with the new URI in the Location header. The body may be empty or a minimal representation. Include relevant headers such as Content-Type matching the created resource; Content-Length: 0 indicates no body. Server responses MUST use entity tags for responses that contain resource representations or successful responses to HEAD requests, enabling concurrency control in subsequent operations.
On success, return 201 Created with the new URI in the `Location` header. The body may be empty or a minimal representation. Server responses MUST use entity tags for responses that contain resource representations or successful responses to HEAD requests, enabling concurrency control in subsequent operations.
If the target container `/alice/notes/` does not exist, the server MUST return a 404 error status unless another status code is more appropriate.

This comment was marked as resolved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

(auto-creation of target containers is probably also an optional capability, cfr the discussion of multi-parent containment of today)

@TallTed TallTed Feb 27, 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.

MUST [...] unless is a sign of multiple steps having been compressed into one. This often has some utility for humans, but it is a terrible way to specify software algorithms. Without reviewing the completeness or correctness of the analysis above, I will simply suggest that such compressed steps be de-compressed and each such algorithmic expression be stated with complete atomicity.

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.

Given that this is not a section of the spec which was modified in this PR I would propose to split this off into a separate issue.

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.

See #87

This creates a new container at `/alice/notes/`, with server-generated metadata including `rel="type"` as `https://www.w3.org/ns/lws#Container`.

**Additional notes on Create (HTTP binding):**
* POST is not idempotent. Repeating it may create duplicates; clients SHOULD avoid unintentional retries or use unique identifiers/checks to prevent this.

This comment was marked as resolved.

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.

Humans rarely discuss recursive create or recursive delete, except in context of UNIX-like environments, and even there, recursive delete is only spoken of in context of specific implementations. Humans want to "delete this folder and everything in it", or "(copy or move) this folder and all its contents to that other location".

I do not think that recursive create and/or recursive delete should be tied together, because they do not really reflect the same capability, especially once they get described with full algorithmic steps. I may be proven wrong when such expression exists, but until that point I strongly believe that each activity should be explored only as itself, as I think it very likely that some implementation(s) will not support both of these conceptual features.

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.

@bjdmeest Could you maybe raise a separate issue clarifying what you mean by "recursive creation"?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

yes, related are #87 and #88

The delete resource operation is implemented using the HTTP DELETE method, as defined in the abstract operation above. This section specifies the HTTP bindings for inputs, behaviors, and responses.

The DELETE request targets the URI of the resource or container to remove. Clients MAY include an If-Match header with an ETag for concurrency checks, as described in the abstract operation.
The DELETE request targets the URI of the resource or container to remove. Clients MAY include an `If-Match` header with an ETag for concurrency checks, as described in the abstract operation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think mentions of 'abstract operation' is no longer relevant?

For non-container resources, the server removes the resource content, its associated metadata (linkset), and the containment reference in the parent container.

On success, the server MUST respond with 204 No Content. Servers SHOULD support concurrency checks via If-Match with ETags; mismatches MUST yield 412 Precondition Failed.
For container resources, the server defaults to non-recursive deletion. If the container is not empty and recursion is not requested, the server MUST reject the request with 409 Conflict. If recursion is desired and supported, clients MUST use the `Depth: infinity` header, as defined in [[RFC4918]]. Servers that do not support recursion MUST reject such requests with 501 Not Implemented.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

501 gives the impression that the server is not spec-compliant (but spec-aware). Why not either 500 or 405 and assume 'support for recursion' is an additional capability?

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.

In general, if a client supplies a header that is not supported by a server, the server simply ignores it. I would suggest aligning this behavior with general practice.

This file belongs in the multiple containment branch, not the
single containment base.
| System Managed | Maintained by the server; Read-Only. Includes acl, linkset, type, representation, sizeInBytes, modified. |
| Core Metadata | Managed by the client (subject to server restrictions). Includes partOf, contains, title, creator. |
| System Managed | Maintained by the server; Read-Only. Includes `acl`, `linkset`, `type`, `mediaType`, `size`, `modified`. |
| Core Metadata | Managed by the client (subject to server restrictions). Includes `up`, `items`, `title`, `creator`. |

This comment was marked as resolved.

Comment thread lws10-core/Operations/metadata.md Outdated
|------------|------------|
| System Managed | Maintained by the server; Read-Only. Includes acl, linkset, type, representation, sizeInBytes, modified. |
| Core Metadata | Managed by the client (subject to server restrictions). Includes partOf, contains, title, creator. |
| System Managed | Maintained by the server; Read-Only. Includes `acl`, `linkset`, `type`, `mediaType`, `size`, `modified`. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

acl is probably old

Comment thread lws10-core/Operations/metadata.md Outdated
- Replacement (PUT): If advertised in the Allow header, a client MAY replace the entire linkset. If the server does not support PUT, it MUST reject the request with 405 Method Not Allowed.

- Restrictions: Servers MAY restrict modifications to specific links (like partOf or contains) to maintain system integrity. If a server restricts partOf modifications, it MUST document this in its conformance statement.
- Restrictions: Servers MAY restrict modifications to specific links (like `up` or `items`) to maintain system integrity. If a server restricts `up` modifications, it MUST document this in its conformance statement.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First time 'conformance statement' is mentioned

Comment thread lws10-core/Operations/read-resource.md Outdated
In all cases, the server MUST include the following metadata in the response headers: an ETag (representing the listing version, which changes on membership modifications), and Link headers with rel="type" indicating it is a container, rel="linkset", rel="partOf", and rel="acl".
In this example, `/alice/notes/` is a container. The response uses JSON-LD with the LWS context, listing members with required metadata. Each item includes its `type`, `id`, `mediaType`, `size`, and `modified` timestamp as flat properties.

In all cases, the server MUST include the following metadata in the response headers: an ETag (representing the listing version, which changes on membership modifications), and Link headers with `rel="type"` indicating it is a container, `rel="linkset"`, `rel="up"`, and `rel="acl"`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

acl is mentioned


### Container Creation
Container instantiation occurs via the standard resource creation operation (Section 7.1), differentiated by an indicator specifying the intent to establish a container rather than a non-container resource. This process yields an empty container amenable to subsequent population with members, including sub-containers to extend the hierarchy. Servers MUST assign identifiers, and empty containers MUST be supported.
### Single Containment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As said during the call: I would refrain from restricting too much: instead, specify minimal MUSTs that do not preclude the option for multiple containment, but also not necessarily mention it already. Now this feels too strict: multiple-containment conformant servers should also 100% fulfill the requirements that are described below

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.

Move this to a separate PR and leave out the single containment text.

@laurensdeb laurensdeb marked this pull request as ready for review February 27, 2026 16:02

@pchampin pchampin left a comment

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 have reviewed everything except the section about Operations.

Comment thread lws10-core/Operations/create-resource.md Outdated
Use POST to add a new resource inside an existing container. The server assigns an identifier to the resource, optionally suggested via the Slug header. The server MAY honor the Slug header if it does not conflict with naming rules or existing resources. Clients MUST include a Content-Type header in the request to indicate the media type of the new resource, enabling the server to distinguish between resource types. Specifically, servers MUST interpret the Content-Type as follows: if it matches the LWS-defined media type for containers (application/lws+json), the server creates a Container; otherwise, it creates a DataResource with the specified media type.
Use POST to add a new resource inside an existing container. The server assigns an identifier to the resource, optionally suggested via the `Slug` header. The server MAY honor the Slug header if it does not conflict with naming rules or existing resources. Clients indicate the type of resource to create as follows:

- To create a **Container**, the client MUST include a `Link` header with `rel="type"` pointing to the Container type: `Link: <https://www.w3.org/ns/lws#Container>; rel="type"`. The request body MAY be empty.

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.

this partially addresses #77 but I'm still concerned about "the request body MAY be empty". I would rather have MUST here.

If that remains a MAY, we should therefore specify which content-type is allowed, and with which constraints (we can not let clients post arbitrary application/lws+json for creating a container, e.g. trying to pre-populate the container).

Comment thread lws10-core/index.html Outdated
Comment on lines +9 to +10
- **Container** — a resource that contains other resources.
- **DataResource** — a data-bearing resource (e.g., a document, image, or structured data file).

This comment was marked as resolved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@pchampin Essentially auxiliary resources like in Soild. The notion is important, so as to have general and extendible specification over operations over them. See #67

OTOH, Adding this as a category in above list may be is a category error. The distinction b/w containers and non-cotainers (data resources here) is about their intrinsic property of mereological capability. While distinction b/w primary resources and auxiliary/metadata resources is about their extrinsic property of their place in the layout relative to other resources. Thus that could be other axis of categorization based on place. Which has 3 categories of (storage root, contained, auxiliary/metadata).

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.

@damoo yes, basically what I'm after is re-introducing the notion of "auxiliary resource" as defined by Solid.

You are also not wrong about the "category error", but I would argue the current list is already more than just about mereology. A data resource is not any kind of leaf (i.e. non-container resource), but is the intersection of leaf and of your contained category... (granted, the current definition is not explicit about it, but I assume that this was the intent).

Another way to look at it is to consider two dimensions: whether a resource can contain other resources (container/leaf), and whether a resource is created/deleted by the server or by a client's request.

server-managed client-managed
container storage root contained container
leaf auxiliary resource data resource

The "storage root" category being a singleton (at least for each storage), I find it acceptable to present it as a special case of the more general category of "container", rather than as a separate category.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@pchampin , Why I am after those semantics is: I want an "auxiliary container"/"metadata container" to hold METS metadatata with it's xml linking to other rdf metadata files in that container. Thus being container resource and metadata resource need not be mutually exclusive.

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 sorry, I really don't understand your comment here. What is METS metadata? what has xml to do with this?

Comment on lines +30 to +31
- **No orphans**: Every non-root resource MUST be reachable from the root container through the containment hierarchy.
- **No cycles**: The containment hierarchy MUST form a tree. A container MUST NOT directly or indirectly contain itself.

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.

Noting that these two points are direct consequences of the "7.2 Single Containment", so it is a bit odd to repeat that here in the current state of the doc.

That being said, if (when?) 7.2 is relaxed to allow some implementations to support multiple-containment, then they will make sense. As I am in favor of eventually relaxing 7.2, let's keep them here for the moment :)


A contained resource description SHOULD include:

- **`mediaType`**: The media type of the resource (e.g., `"text/plain"`, `"image/jpeg"`). MUST be present for DataResources.

This comment was marked as resolved.

Comment thread lws10-core/container-representation.md Outdated
- **`size`**: The size of the resource in bytes, expressed as an integer.
- **`modified`**: The date and time the resource was last modified, expressed as an ISO 8601 date-time string.

#### Property Summary

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.

this table is barely more concise than the text above, and creates redundancy (which is error prone during maintenance).

I would rather remove it (but can live with it if I have to).

For each core operation (create, read, update, delete), we describe the HTTP method(s) to use, required headers or special considerations (including concurrency controls via ETags, content negotiation, and pagination for container listings), and what the server should do and return. Standard HTTP status codes are used to indicate outcomes with additional mappings for scenarios such as quota exceeded (507 Insufficient Storage) or precondition failures (412 Precondition Failed). The binding tries to adhere to HTTP/1.1 and relevant RFCs (such as [[!RFC7231]] for HTTP semantics, [[!RFC7233]] for range requests, [[!RFC5789]] for PATCH, [[!RFC8288]] for Web Linking, and [[!RFC9264]] for Link Sets) so that it integrates naturally with web standards. Discoverability is emphasized through mechanisms like Link headers and WWW-Authenticate headers on 401 responses, avoiding hardcoded URI locations. Metadata integration is required across operations, ensuring atomicity and use of Link Sets for server-managed and user-managed properties.

**Note:** As all examples in this specifications, examples given in this section (HTTP request and response snippets) are **non-normative**, meant to illustrate typical usage. The actual requirements are stated in the descriptive text and tables. Also, while this binding covers HTTP (as the initial target protocol), the LWS operations could in principle be bound to other protocols in the future. Servers SHOULD support content negotiation for formats like JSON-LD (with normative contexts and optional framing for containers) and Turtle, using custom media types such as 'application/lws+json' where appropriate. No newline at end of file
**Note:** As all examples in this specifications, examples given in this section (HTTP request and response snippets) are **non-normative**, meant to illustrate typical usage. The actual requirements are stated in the descriptive text and tables. Also, while this binding covers HTTP (as the initial target protocol), the LWS operations could in principle be bound to other protocols in the future. Servers MUST support content negotiation for `application/lws+json`, `application/ld+json`, and `application/json` for container representations (see [Container Media Type](#container-media-type)). Servers MAY additionally support formats like Turtle. No newline at end of file

This comment was marked as resolved.

Comment thread lws10-core/Operations/metadata.md Outdated
- Optional target attributes: Additional key-value pairs that further describe the link or the target resource.

Metadata distinguishes between resources and their representations, allowing for multiple media types where applicable. For containers, metadata includes membership details and supports pagination to handle large sets efficiently. For DataResources, metadata includes representations, each with mediaType and optional sizeInBytes.
Metadata distinguishes between resources and their representations, allowing for multiple media types where applicable. For containers, metadata includes membership details. For DataResources, metadata includes media type and size information.

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.

"metadata includes membership details"

This is confusing. The paragraph above says that "All metadata in LWS is expressed as a set of typed link", which is not the case of membership detail. So membership details is not "metadata" as defined here.

Furthermore, as the membership details are part of the representation of the container, they indeed feel more like "data" than "metadata".

@@ -0,0 +1,73 @@
### Container Representation

This comment was marked as resolved.

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.

Resolve this through issue #67

Use POST to add a new resource inside an existing container. The server assigns an identifier to the resource, optionally suggested via the `Slug` header. The server MAY honor the Slug header if it does not conflict with naming rules or existing resources. Clients indicate the type of resource to create as follows:

- To create a **Container**, the client MUST include a `Link` header with `rel="type"` pointing to the Container type: `Link: <https://www.w3.org/ns/lws#Container>; rel="type"`.
- To create a **DataResource**, the client includes the resource content in the request body with the appropriate `Content-Type` header.

@TallTed TallTed Feb 27, 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.

This is one of those things that the user will want to do in one step ("{put|copy|mov} this folder and all its contents there"), which the software may need to do in several (create a container named xyz at location bcd, and put each of these documents inside it; and (for a move) after all that has succeeded, delete the originals).

Several pieces of ACID consideration come into play. We should NOT try to reinvent specifications for all these processes and activities, but learn from the wheels that already exist, and re-implement the things that have been previously specified.

```
On success, return 201 Created with the new URI in the Location header. The body may be empty or a minimal representation. Include relevant headers such as Content-Type matching the created resource; Content-Length: 0 indicates no body. Server responses MUST use entity tags for responses that contain resource representations or successful responses to HEAD requests, enabling concurrency control in subsequent operations.
On success, return 201 Created with the new URI in the `Location` header. The body may be empty or a minimal representation. Server responses MUST use entity tags for responses that contain resource representations or successful responses to HEAD requests, enabling concurrency control in subsequent operations.
If the target container `/alice/notes/` does not exist, the server MUST return a 404 error status unless another status code is more appropriate.

@TallTed TallTed Feb 27, 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.

MUST [...] unless is a sign of multiple steps having been compressed into one. This often has some utility for humans, but it is a terrible way to specify software algorithms. Without reviewing the completeness or correctness of the analysis above, I will simply suggest that such compressed steps be de-compressed and each such algorithmic expression be stated with complete atomicity.

This creates a new container at `/alice/notes/`, with server-generated metadata including `rel="type"` as `https://www.w3.org/ns/lws#Container`.

**Additional notes on Create (HTTP binding):**
* POST is not idempotent. Repeating it may create duplicates; clients SHOULD avoid unintentional retries or use unique identifiers/checks to prevent this.

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.

Humans rarely discuss recursive create or recursive delete, except in context of UNIX-like environments, and even there, recursive delete is only spoken of in context of specific implementations. Humans want to "delete this folder and everything in it", or "(copy or move) this folder and all its contents to that other location".

I do not think that recursive create and/or recursive delete should be tied together, because they do not really reflect the same capability, especially once they get described with full algorithmic steps. I may be proven wrong when such expression exists, but until that point I strongly believe that each activity should be explored only as itself, as I think it very likely that some implementation(s) will not support both of these conceptual features.

Comment thread lws10-core/Operations/read-resource.md Outdated
* **Behavior**:
* For non-container resources, the server returns the resource content.
* For containers, the server returns a listing of member resources. Listings must include core metadata for each member and must be filtered based on the requester's permissions.
* For containers, the server returns a listing of all member resources. Listings must include core metadata for each member.

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 change would seem to violate permissions, as it would require the server to return a listing of "all member resources" including those for which I hold no READ permissions.

Similarly, I think that the preceding line should perhaps say, "the server returns the resource content IFF the requester has READ permissions on that resource."

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.

We should also be careful of the word "all" here, as that could be construed to mean that paging is not possible

Content-Length: 0
```
On success, return 201 Created with the new URI in the Location header. The body may be empty or a minimal representation. Include relevant headers such as Content-Type matching the created resource; Content-Length: 0 indicates no body. Server responses MUST use entity tags for responses that contain resource representations or successful responses to HEAD requests, enabling concurrency control in subsequent operations.
On success, return 201 Created with the new URI in the `Location` header. The body may be empty or a minimal representation. Server responses MUST use entity tags for responses that contain resource representations or successful responses to HEAD requests, enabling concurrency control in subsequent operations.

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.

Note that ETags should not be part of the successful response to a creation request. See #62

```
HTTP/1.1 201 Created
Location: /alice/notes/
ETag: "container-new-123"

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.

An ETag is for representations. A response with no content should not have an etag header. It will mess with caches

For non-container resources, the server removes the resource content, its associated metadata (linkset), and the containment reference in the parent container.

On success, the server MUST respond with 204 No Content. Servers SHOULD support concurrency checks via If-Match with ETags; mismatches MUST yield 412 Precondition Failed.
For container resources, the server defaults to non-recursive deletion. If the container is not empty and recursion is not requested, the server MUST reject the request with 409 Conflict. If recursion is desired and supported, clients MUST use the `Depth: infinity` header, as defined in [[RFC4918]]. Servers that do not support recursion MUST reject such requests with 501 Not Implemented.

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.

In general, if a client supplies a header that is not supported by a server, the server simply ignores it. I would suggest aligning this behavior with general practice.

On success, the server MUST respond with 204 No Content. Servers SHOULD support concurrency checks via If-Match with ETags; mismatches MUST yield 412 Precondition Failed.
For container resources, the server defaults to non-recursive deletion. If the container is not empty and recursion is not requested, the server MUST reject the request with 409 Conflict. If recursion is desired and supported, clients MUST use the `Depth: infinity` header, as defined in [[RFC4918]]. Servers that do not support recursion MUST reject such requests with 501 Not Implemented.

On success, the server MUST respond with 204 No Content. Servers SHOULD support concurrency checks via `If-Match` with ETags; mismatches MUST yield 412 Precondition Failed.

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.

For concurrency checks, there is more than just If-Match. I would suggest being more generic here and just refer to conditional requests. See also #62

Comment thread lws10-core/Operations/read-resource.md Outdated
* **Behavior**:
* For non-container resources, the server returns the resource content.
* For containers, the server returns a listing of member resources. Listings must include core metadata for each member and must be filtered based on the requester's permissions.
* For containers, the server returns a listing of all member resources. Listings must include core metadata for each member.

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.

We should also be careful of the word "all" here, as that could be construed to mean that paging is not possible


### Resource Identification

Resources are identified by URIs. The URI of a resource is independent of its position in the containment hierarchy. Servers assign URIs during resource creation and MAY incorporate client hints (e.g., the `Slug` header), but clients MUST NOT assume that URI structure reflects containment.

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.

Is "clients MUST NOT assume ..." too rigid? If another specification builds on LWS but adds requirements related to URI structure, this MUST NOT statement could get in the way. I would at least change it to SHOULD NOT

Co-authored-by: Pierre-Antoine Champin <pierre-antoine@w3.org>
@gibsonf1

gibsonf1 commented Mar 2, 2026

Copy link
Copy Markdown

This definition of data resource in terminology section precludes non-files - how can that be correct?

"data resource — a data-bearing resource such as a document, image, or structured data file."

|------------|------------|
| System Managed | Maintained by the server; Read-Only. Includes acl, linkset, type, representation, sizeInBytes, modified. |
| Core Metadata | Managed by the client (subject to server restrictions). Includes partOf, contains, title, creator. |
| System Managed | Maintained by the server; Read-Only. Includes `linkset`, `type`, `mediaType`, `size`, `modified`. |

This comment was marked as resolved.

@gibsonf1

gibsonf1 commented Mar 2, 2026

Copy link
Copy Markdown

" root container — the top-level container in an LWS storage. The root container has no parent and acts as the entry point for the storage hierarchy. "

Shouldn't this be plural as in there can be multiple root-level containers.

@gibsonf1

gibsonf1 commented Mar 2, 2026

Copy link
Copy Markdown

"linkset — A separate resource associated with each LWS resource that contains the complete set of typed links (metadata) for that resource, as defined in [ RFC9264 ]. The linkset is discovered via a rel="linkset" link relation and can be modified to manage resource relationships, including containment."

A linkset is not a separate resource necessarily, that is implementation specific (It would not be a separate resource in the TwinPod case), but it is a separate representation.

@gibsonf1

gibsonf1 commented Mar 2, 2026

Copy link
Copy Markdown

7.1.. "Every LWS storage has a root container that serves as " should be has "one or more root containers"

@gibsonf1

gibsonf1 commented Mar 2, 2026

Copy link
Copy Markdown

"The root container has no parent " The LWS storage has no parent

@gibsonf1

gibsonf1 commented Mar 2, 2026

Copy link
Copy Markdown

Recommend that up includes an array of up resources to root container: "the rel="up" link relation. Servers "
(This is what TwinPod currently does so apps can understand where things are)

@gibsonf1

gibsonf1 commented Mar 2, 2026

Copy link
Copy Markdown

How does it make sense to list things that user has no access to and provide an implementation note specific so some particular implementation?
" Filtering container listings are server-managed based on individual resource access could have significant performance implications and complicates caching. "

Comment thread lws10-core/index.html Outdated
<li><dfn>container</dfn> &mdash; An LWS resource that maintains links to a set of contained resources whose lifecycle is governed by the same LWS server. Containers serve as organizational units enabling clients to group, discover, and navigate resources.</li>
<li><dfn>data resource</dfn> &mdash; a data-bearing resource such as a document, image, or structured data file.</li>
<li><dfn>contained resource</dfn> &mdash; A LWS resource, either a <a>container</a> or a <a>data resource</a>, that is referenced by one or more containers through a containment relationship.</li>
<li><dfn>root container</dfn> &mdash; the top-level container in an LWS storage. The root container has no parent and acts as the entry point for the storage hierarchy.</li>

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.

Replace this with a top-level container


<div class="note" role="note">
<p><b>Authorization Considerations</b></p>
<p>Filtering container listings based on individual resource access could have significant performance implications and complicates caching.</p>

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.

Remove this note

@laurensdeb laurensdeb requested review from acoburn and pchampin March 2, 2026 16:19

@acoburn acoburn left a comment

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.

As discussed in LWS meeting on 2 Mar, 2026, I voted +1 to merge this

@laurensdeb laurensdeb merged commit 24c33ee into main Mar 2, 2026
1 check passed
@laurensdeb laurensdeb deleted the containers-base branch March 2, 2026 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LWS Container Media Type

8 participants