Some HTTP APIs expose paths like `/me`, `/settings`, or `/orders/{id}/status` that are not collections and have no id in the URL. What are these singleton resources, when are they the right choice, and which HTTP methods make sense on them?
answer
- one instance per scope → no id in the URI
- GET + PUT/PATCH; rarely POST; DELETE only if absence is valid
- split for cache/permission/polling boundaries
- /me is an alias — canonical URI + private caching
- unset singleton → 404, PUT creates with 201
basics
~20 sA singleton is a resource that exists exactly once in its context, so it needs no id: /me, /config, /orders/42/status. Use GET to read and PUT/PATCH to update. There is usually no POST (nothing to create) and often no DELETE.
solid answer
~50 sA **singleton resource** is one instance within its scope, addressed without an identifier — either globally (`/config`) or relative to a parent (`/orders/42/shipping-address`) or to the caller (`/me`). Methods: - `GET` — read it. - `PUT` — replace it wholesale; naturally idempotent and the usual update verb here. - `PATCH` — partial update. - `POST` — normally absent: there is nothing to create, since the singleton always exists. - `DELETE` — only if "absent" is a meaningful state (clearing an optional shipping address). If the concept cannot be absent, do not offer it. Use them when exactly one instance exists per scope and clients never enumerate: user-scoped aliases (`/me`), configuration, a sub-part of a parent that is 1:1 and worth its own cache and permission boundary. Two cautions: `/me` is an alias, so return the canonical URI (`/users/u1`) in the body or a `Content-Location` header, and remember it makes responses caller-dependent, so shared caches must not treat it as one entity.
code
http · 10 linesGET /users/7/shipping-address HTTP/1.1
404 Not Found
PUT /users/7/shipping-address HTTP/1.1
Content-Type: application/json
{"line1":"1 Main St","city":"Berlin"}
201 Createdgo deeper
Define it as a resource with exactly one instance per scope and no id, and give GET plus PUT/PATCH as the methods.
Explain why you would split a 1:1 part out of its parent — cache lifetime, permission, cheap polling — and handle the not-yet-created case.
Cover PUT-creates semantics with 201, DELETE only where absence is valid, and the caching, logging and aliasing consequences of /me.
Frame singletons as deliberate boundary choices and set the house convention: singular naming, canonical URIs behind aliases, and documented absence semantics.
## What a singleton resource is Most resources come in collections: `/orders` holds many, `/orders/42` is one of them, and the id in the path selects which. A **singleton** has no such choice — within its scope there is exactly one, so the URI carries no identifier. Three common flavours: 1. **Global singleton** — `/config`, `/health`, `/status`. One per deployment. 2. **Sub-resource singleton** — `/orders/42/status`, `/orders/42/shipping-address`, `/users/7/avatar`. A 1:1 part of a parent, split out because it deserves its own cache lifetime, permission, or update path. 3. **Caller-scoped alias** — `/me`, `/session`. Exactly one per authenticated principal; the server resolves the identity from credentials rather than the path. ## Why split a singleton out of its parent If `/orders/42/status` is one field of the order, why give it a URI? Because a resource boundary is also a **cache**, **permission**, and **concurrency** boundary. - A status that changes every few seconds inside an order representation that is otherwise stable ruins the order's cacheability; split, the order caches for minutes and the status for seconds. - Updating just the status may be a different permission (a warehouse worker may set status but not edit line items). A separate resource makes that authorization boundary structural rather than field-by-field. - Polling a small representation is far cheaper than re-fetching the whole order. Do not split when the part is meaningless alone, or when it must change atomically with the rest of the parent. ## Method semantics `GET` is straightforward. `PUT` is the characteristic write: because the resource always exists and the request states its complete desired value, `PUT` is idempotent and unambiguous — retrying after a timeout is safe. `PATCH` handles partial changes when the representation is large. `POST` is usually wrong on a singleton: there is nothing to create, and "create if missing" is exactly what `PUT` already expresses. If you find yourself wanting `POST /orders/42/status` to *change* status, you are reaching for an action, which is a different modelling question — a state field takes `PUT`/`PATCH`. `DELETE` is offered only when absence is a legitimate state. `DELETE /users/7/avatar` (revert to default) is meaningful; `DELETE /orders/42/status` is not, because an order always has a status. If you offer `DELETE`, define what a subsequent `GET` returns: `404`, or `200` with a default. Both are defensible; pick one and document it. A singleton that may not exist yet is a real design point: `GET /users/7/shipping-address` before one is set should return `404` (the resource does not exist) rather than `200` with nulls, and `PUT` then creates it, answering `201 Created` the first time and `200`/`204` on subsequent replacements. ## The `/me` alias, specifically `/me` is convenient because the client does not need to know its own id to make the first call. But it is an **alias**, and aliases have consequences: - **Two URIs for one resource.** Keep `/users/{id}` canonical; return the canonical URI in the body, and consider a `Content-Location: /users/u1` header so a client can learn its real address. - **Caching.** The response depends entirely on the credentials, so it must not be cached by a shared cache as one entity. Mark it private, and make sure any intermediary keys on the authorization context. - **Logs and debugging.** Every request looks like `/me`, so the logs must carry the resolved principal or you cannot tell whose data was served. - **Redirect option.** Some APIs answer `/me` with `302`/`303` to the canonical URI, which is clean but costs a round trip and confuses simple clients; returning the representation directly with `Content-Location` is more common. ## Naming Singletons take singular names — `/config`, `/status`, `/me` — precisely because there is one. That singular/plural contrast is a useful signal to readers of the API: plural means a collection you can list and filter; singular means one thing you read and replace.
- Should `GET /users/7/shipping-address` return 200 with nulls or 404 when no address is set?`404` — the URI names a resource that does not currently exist, and a body of nulls is indistinguishable from an address whose fields are genuinely empty. `PUT` then creates it and answers `201 Created` the first time. Whichever you choose, document it, because clients branch on it.
- What is the downside of `/me`?It is a second URI for a resource that already has a canonical one, and its response depends entirely on the caller's credentials, so it cannot be cached by shared caches as a single entity and must be marked private. It also flattens logs, since every request looks identical until you resolve the principal. Returning the canonical URI in the body or a `Content-Location` header mitigates the aliasing.
saying these in an interview costs you the question
- Using POST to update a singleton when PUT already expresses the idempotent replacement
- Returning 200 with an all-null body for a singleton that has never been set
- Treating `/me` as the canonical URI and never exposing the real one
- Allowing a shared cache to store a `/me` response without keying on the caller
- Pluralising a singleton's name (`/configs`) when only one instance can ever exist