3.3 The store pattern: one client codepath for every store

Several RS2 services — file, data, the pipeline/query authoring surfaces, and the code-deployment surface — are stores. They all obey a single normative contract, so one client can drive any of them. Learn it once here; Part 4 applies it in detail.

The contract

A store is a tree of containers and resources (children). Trailing slash means container; no trailing slash means a child.

Request Behavior (identical on every store)
GET <container>/ A listing: application/vnd.rs2.dir+json{path, entries: [{name, dir, …}], total} plus an X-Total-Count header. Works at every level, including the mount root. Paginate with $take / $skip
GET <child> The resource, with a version ETag
PUT <child> Upsert — 201 created or 200 overwritten, empty body, ETag
POST <container>/ Keyless create under a server-generated name → 201 + Location
DELETE <child> 204
DELETE <container>/ 204 if empty/unguarded; non-empty → 409; retry with ?confirm=<container name>204

That's the entire shape. Containers nest, and a listing entry with "dir": true is itself a container you can list.

The generic client loop

Because the shape is fixed, a polymorphic client needs exactly one algorithm:

  1. Walk containers with trailing-slash GETs.
  2. Recurse into entries where dir is true.
  3. Read and write children directly.
  4. On a 409 from a container delete, retry with ?confirm=<name>.

An editor UI, a sync tool, or a backup script written against this loop works unchanged across file, data, deployed code, and any future store (S3, SQL) that joins by passing the same conformance suite.

Differences are facets, not special cases

Real services do differ — but those differences are declared as facets on the discovery surface, not baked into the client by service name:

  • rangefile supports Range: requests (4.2).
  • schema, patch, echodata's validation, merge-PATCH, and return-the-stored-record behaviors (4.4).
  • confirm-delete — the ?confirm= container guard.
  • content-addressed — the code store names children by content hash (8.7).
  • static-site — a file mount configured to serve a site (4.3).

The rule is feature-detect, never special-case the service name. Ask GET /.well-known/rs2/services what facets a mount declares (9.1), then light up behavior accordingly. The generated OpenAPI reflects this structurally: every store path references the same shared path-item shapes.

The next section generalizes this idea — patterns and facets — to the whole service surface.


Previous: 3.2 Tenants and mounts · Manual home · Next: 3.4 Patterns vs. facets →