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:
- Walk containers with trailing-slash
GETs. - Recurse into entries where
diristrue. - Read and write children directly.
- On a
409from 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:
range—filesupportsRange:requests (4.2).schema,patch,echo—data'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— afilemount 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 →