skip to content

Resources and URIs

Turning a domain into addressable resources and giving them URLs that stay sane as the API grows: nouns, collections versus singletons, nesting depth, and where query parameters belong. Interviewers ask because URL design is the first thing consumers see and the hardest thing to take back.

part ofAPI stylesoverview, primer and where to startread it →
on this pageshow

questions

16

When designing URL paths for an HTTP API, what naming conventions do you follow, and why is POST /createUser considered worse than POST /users?

level: juniorimportance: must knowfreq 72%

answer

  1. URL = noun, method = verb
  2. plural collections, id beneath
  3. lowercase-with-hyphens
  4. no .json extension — use Accept
  5. pick one trailing-slash form

basics

~10 s

Paths name things, not actions: nouns, usually plural collections (/users, /users/42/orders). The HTTP method supplies the verb, so POST /users beats POST /createUser. Verbs in paths duplicate the method and multiply near-identical endpoints.

solid answer

~40 s

A URL identifies a **resource** — a thing — so path segments are nouns and the HTTP method carries the action. `POST /users` creates, `GET /users/42` reads, `DELETE /users/42` removes. `POST /createUser`, `POST /getUser`, `POST /deleteUser` encode the verb twice and discard what HTTP already gives you: uniform semantics, safe/idempotent knowledge, cacheability of GET, and generic tooling. Conventions I apply: - **Plural collection names** (`/orders`) with the item beneath (`/orders/{id}`). - **Hierarchy for containment**: `/customers/{id}/addresses`. - **Lowercase, hyphen-separated multi-word segments**: `/purchase-orders`. - **No file extensions** (`.json`) — negotiate with the `Accept` header. - **No trailing slash**, applied consistently. The payoff is predictability: a client who has seen two endpoints can guess the third, and caches/proxies can reason about the traffic.

go deeper

for a junior

Say that the path names a resource and the HTTP method is the verb, give the /users example, and mention plural collections and lowercase-hyphen segments.

for a middle

Add the concrete rules — no file extensions, one trailing-slash form enforced by redirect — and explain why verbs in paths cause endpoint sprawl.

for a senior

Frame it as contract predictability and tooling: consistent naming lets caches, gateways, and generated clients work without per-endpoint knowledge; call out where the convention legitimately bends.

for a principal

Discuss naming as governance — a style guide plus linting on the OpenAPI spec, how you migrate a legacy verb-shaped surface, and the cost of URL churn across many client teams.

## URLs identify, methods act A URL in an HTTP API is an **identifier for a resource** — a noun-like thing: a user, an order, a collection of orders. The *action* is carried by the HTTP method: GET reads, POST creates or submits, PUT replaces, PATCH partially updates, DELETE removes. Every naming convention below protects that split. `POST /createUser` states the verb twice, and worse, it makes the path the place where actions live. Once that door is open the surface grows one endpoint per verb — `/createUser`, `/updateUser`, `/deactivateUser`, `/getUserByEmail` — each needing its own documentation, each opaque to anything generic sitting in the request path. With `POST /users` plus `GET /users/{id}` a reader already knows the shape of every other collection in the API. ## Plural collections The dominant convention is plural collection names with the member nested under it: `/orders` and `/orders/9f3`. The plural reads correctly for what the collection URL returns (a list) and keeps the member path a straightforward narrowing. Singular (`/order/9f3`) is defensible but consistency matters far more than the choice — an API that mixes `/users` and `/order` forces the reader to memorise instead of infer. Genuine singletons — a resource of which exactly one exists per parent — are the legitimate exception: `/users/42/avatar`, `/me/settings`. ## Casing and separators Path segments are lowercase; multi-word segments use hyphens: `/purchase-orders`, `/shipping-addresses`. Two reasons. Hosts are case-insensitive while paths are case-sensitive, so mixed case in paths creates a class of near-miss 404s that look like server bugs. And hyphens are the long-standing web convention that search engines, humans, and CLI users all read comfortably; underscores can be hidden by underlining in some UIs, and camelCase collides with the case-sensitivity trap. Query parameter *names* and JSON body fields are a separate matter — those usually follow the body's language convention (`camelCase` or `snake_case`); the hyphen rule is about path segments. ## No file extensions `/users/42.json` bakes a representation format into the identity of the resource. Format is a **representation** concern, negotiated per request with `Accept: application/json` and answered with `Content-Type`. If you need format in the URL as a pragmatic escape hatch for browsers or dumb clients, a query parameter (`?format=csv`) is less damaging than an extension, because the resource identity stays intact. ## Trailing slashes `/users` and `/users/` are, strictly speaking, different URLs, and different frameworks disagree about whether they are the same route. Pick one form (usually no trailing slash), enforce it in the router, and make the other form a `301` permanent redirect rather than a silent alias — that keeps caches, logs, and analytics from splitting one resource across two keys. ## Stability URLs are the API's public vocabulary. Avoid encoding anything volatile into a path segment: internal team names, storage technology, the current org chart, or a mutable display name. Segments that change force clients to change. Prefer identifiers that will outlive the current implementation.

  • Is there ever a legitimate reason to put a verb-like word in an HTTP API path?
    Yes — for operations that genuinely are not create/read/update/delete on a resource, such as cancelling an order or rotating a key. The usual treatments are a state-transition sub-resource or an explicitly-marked custom method segment. The point of the noun convention is not verb-phobia; it is that CRUD-shaped work should not invent verbs it does not need.
  • Singular or plural collection names — does the choice actually matter?
    Far less than consistency. Plural is the majority convention and reads correctly for a list endpoint, so it is the safer default in a new API. What genuinely costs teams money is mixing the two, because every endpoint then has to be looked up rather than guessed. True singletons under a parent are the one clean exception.

saying these in an interview costs you the question

  • Claiming REST forbids verbs anywhere, including in custom action names
  • Mixing /users and /order in one API and calling it a style preference
  • Putting .json in the path and calling that content negotiation
  • Treating /users and /users/ as automatically identical across all servers
  • Using camelCase path segments and being surprised by case-sensitive 404s

context

open as a page

In an HTTP API, how do you decide whether a value belongs in a path segment such as /orders/{id} or in the query string such as ?status=open?

level: juniorimportance: must knowfreq 66%

basics

~20 s

Path carries identity and hierarchy — what resource you are addressing; it is required and usually part of a single thing's URL. Query carries modifiers on a collection — filtering, sorting, pagination, field selection; these are optional and any combination is valid.

open as a page

When designing an HTTP API, how do you decide between exposing a nested path like `/orders/{orderId}/items` and a top-level collection with a filter like `/items?orderId={orderId}`? What does each choice commit you to?

level: middleimportance: must knowfreq 60%

basics

~20 s

Nest when the child is owned by the parent, has no meaning or identity outside it, and is always accessed through it. Use a top-level collection with a filter when the child is independently identifiable and queried across parents. Many APIs do both: nested for creation and scoped listing, a canonical top-level URI for the item itself.

open as a page

When designing an HTTP API, how do you decide what becomes a resource? Explain why a resource is not simply a database table or a domain entity, and give an example where they differ.

level: middleimportance: must knowfreq 65%

basics

~20 s

A resource is anything worth naming with a URI and giving a representation — driven by what clients need to address, not by storage. Entities usually become resources, but resources also cover projections, computed views, and processes that no table matches, and one entity may back several resources.

open as a page

Your HTTP API needs to let a client cancel an order. Cancelling is not a plain create, read, update, or delete. How do you model it, and what are the options?

level: middleimportance: must knowfreq 62%

basics

~20 s

Three mainstream options: POST a state-transition sub-resource (POST /orders/{id}/cancellation), PATCH the status field, or an explicitly-marked custom method (POST /orders/{id}:cancel). Prefer the sub-resource when the action has its own data or history; keep POST for anything with side effects.

open as a page

An HTTP API has grown paths like `/customers/7/orders/42/items/9001/discounts/3`. What problems does that depth create, and how would you restructure it?

level: juniorimportance: should knowfreq 50%

basics

~20 s

Deep paths force clients to know an entire ancestry to address one thing, break when a resource is reparented, and duplicate handlers per level. Keep nesting to about one level of parent: address the deepest resource by its own top-level URI, /discounts/3, and use nesting only for scoped listing and creation.

open as a page

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?

level: juniorimportance: should knowfreq 40%

basics

~20 s

A 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.

open as a page

Your team is writing a style guide for an HTTP API. What do you specify for casing of path segments, casing of query parameter names, trailing slashes, and why?

level: middleimportance: should knowfreq 44%

basics

~20 s

Path segments: lowercase, hyphen-separated (/purchase-orders) because paths are case-sensitive and hyphens read well. Query parameter names: one convention API-wide, usually camelCase or snake_case matching the JSON body. Trailing slash: pick one form, redirect the other with 301.

open as a page

A client needs to fetch a resource whose identifier is the string "a/b c&d". What goes wrong when that value is placed in a URL path segment versus a query parameter, and how do you handle it correctly?

level: middleimportance: should knowfreq 46%

basics

~20 s

Percent-encode per component: in a path segment a slash must become %2F (a raw / splits segments), space becomes %20; in a query, & and = must be encoded or they split parameters, and + may be read as a space. Many servers reject or pre-decode %2F, so identifiers containing slashes are safer in the query or as an opaque encoded id.

open as a page

How would you design HTTP endpoints for a many-to-many relationship — say users belonging to teams — where the membership itself carries data such as a role and a joined-at timestamp?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Promote the relationship to a first-class resource. POST /teams/{id}/memberships creates one, GET|PATCH|DELETE /memberships/{id} manages it, and both sides list through it (/teams/{id}/memberships, /users/{id}/memberships). A bare link-only relation can instead use PUT/DELETE on /teams/{id}/members/{userId} with no body.

open as a page

An HTTP API has one endpoint per database table, and rendering a single screen takes eleven calls. A colleague proposes one large endpoint that returns everything the screen needs. Evaluate both extremes and describe how you would actually choose the granularity of resources.

level: seniorimportance: should knowfreq 50%

basics

~20 s

Fine-grained resources are chatty and push joins onto clients; one screen-shaped mega-resource couples the API to a UI, ruins caching and invalidation, and grows without bound. Choose by interaction: resources sized to how clients actually use data, with composition for genuinely joint reads and splits where permission, volatility or size differ.

open as a page

When designing resource URIs for an HTTP API, how do you choose between an opaque surrogate identifier such as `/users/8f3c...` and a natural key such as `/users/[email protected]` or `/products/SKU-1234`? What are the consequences of each?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Natural keys are readable but change, collide across scopes, and leak data into URLs and logs. Surrogate ids are stable and neutral, so make them canonical. Support natural-key lookup as a filtered query or a documented alias that redirects to the canonical URI.

open as a page

How would you design HTTP API resource URLs so they remain stable and canonical over years, and what do you do when a resource's human-readable slug changes?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Identify resources by an immutable, opaque id in the path; keep mutable slugs out of identity or treat them as aliases. When a slug changes, keep the id URL canonical and answer old slug URLs with 301 to it. Never reuse a retired identifier.

open as a page

A search endpoint for an HTTP API needs dozens of optional filters, some with lists of hundreds of ids. How do you design the parameters, and at what point do you stop using the query string?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Keep filters as flat, optional, individually-named query parameters with repeated keys or comma lists for multi-values, plus standard sort and paging params. When the query outgrows practical URL limits (roughly 4-8 KB) or needs nested boolean logic, move to a POST search endpoint that takes a JSON body.

open as a page

You inherit an HTTP API where almost every endpoint is a POST to a verb-shaped path returning 200 with a status field in the body. How do you judge whether that is a real problem, and what would you do about it?

level: principalimportance: should knowfreq 34%

basics

~20 s

Judge by cost, not purity: are resources unaddressable, are errors invisible to monitoring and gateways, are reads uncacheable, do retries misbehave? If yes, fix incrementally — model the core entities as addressable resources, use real status codes — or adopt an explicit RPC framework rather than a half-hearted hybrid.

open as a page

Google's API design guidelines allow custom methods written as POST /v1/users/{id}:activate, with a colon before the verb. What problem does that colon-suffix syntax solve, and what are its drawbacks?

level: seniorimportance: nice to knowfreq 32%

basics

~20 s

The colon visibly marks the last part as a named operation rather than a sub-resource, so readers and routers cannot confuse /users/1:activate with a collection /users/1/activate. Drawbacks: unfamiliar outside Google-style APIs, and colons occasionally trip naive routers, proxies, and tooling.

open as a page