skip to content

When would you let a handler accept the same value from more than one request source, and how would you govern it?

level: principalimportance: should knowfreq 38%

answer

  1. one canonical source per value
  2. an alias needs a named client
  3. never for credentials or tenancy
  4. normalise before any policy runs
  5. conflicting copies are a 400

basics

~20 s

Only for a value with no security or billing weight, where a client genuinely cannot send the canonical source. Govern it by naming one canonical source, folding the alias into it early in one place, and rejecting conflicting copies.

solid answer

~50 s

The pull is real: link-driven and embedded clients sometimes cannot set a header, tooling wants a value in a query string it can paste, and a migration may need both spellings alive at once. The cost is that the endpoint now has **two ways to say the same thing**, so every surrounding layer — gateway rules, audit logs, cache keys, rate limits — has to implement the same precedence or quietly disagree with the handler. My rule is: one **canonical** source per value; an alias only with a named client need, never for a credential or an identifier that drives authorization or billing; the alias folded into the canonical value in **one** place before any policy runs, so exactly one reading exists downstream; conflicting copies answered with **400** rather than resolved silently; and usage counted, because an alias with no measurement is permanent by default.

go deeper

for a junior

Take away the default: a value should have one place it comes from, and a second accepted source is a decision someone has to justify rather than a convenience to add.

for a middle

Be able to say why two sources multiply the readings of a request, and name the layers besides the handler that read it and could disagree.

for a senior

Design the mechanism: normalise the alias once before any policy runs, reject conflicting copies, and instrument usage so the alias can eventually be removed.

for a principal

Own the tradeoff explicitly — loud failure now against a quiet split reading later — and require every alias to arrive with a named client, a metric and an end date.

## The question behind the question Accepting a value from two sources looks like a convenience feature, and it is really a **contract** decision: how many ways may a client say the same thing, and who is responsible for knowing which one wins? Every additional source multiplies the readings of a request that must agree, and the layers that read a request are more numerous than they first appear — the handler, any policy or authorization filter, the access log, the cache-key builder, the rate limiter, the edge or gateway rules, and whatever reconstructs the request for a retry or replay. ## When an alias is genuinely justified - **A client that cannot set the canonical source.** Navigation-driven contexts, embedded viewers and link-based flows can send a URL but not a custom header. - **A migration.** Moving an identifier from the query string into the path, or from a body field into a header, needs both accepted while callers move over. - **Human-facing tooling.** A value that has to be pasteable into a URL to be usable at a terminal or in a ticket. Each of those is a named client with a named reason. "Someone might find it easier" is not one, and neither is symmetry for its own sake. ## When it is not - **Credentials.** A token accepted in a query string is written into access logs, proxy logs, browser history and referrer headers, none of which were designed to hold secrets. That is a leak channel, not a convenience. - **Authorization and tenancy identifiers.** A second copy of a tenant or owner id is the ingredient the split-reading failure needs: a policy layer checks one copy, the handler binds the other. - **Anything that prices the request.** Quantities, plan ids and quota keys deserve exactly one reading for the same reason. ## The governance that makes it survivable 1. **Declare a canonical source** and write it in the endpoint's published description. There is one answer to "where does this value live", and the alias is documented as an alias. 2. **Normalise once, early.** A single step before any policy runs folds the alias into the canonical value, so every later reader — handler, filter, log, cache key — sees one value and cannot disagree. Resolving the alias inside the handler is the arrangement that produces split readings, because the layers around it never learned the rule. 3. **Conflict is a client error.** When both sources are present and differ, answer **400** naming both. A silent precedence rule means the client cannot see which value the server acted on, and the server cannot prove it later. 4. **Instrument it.** Count requests that used the alias, ideally by caller. An alias without a usage signal has no evidence for removal and therefore stays forever. 5. **Give it an end.** An alias is a migration with a deadline or it is a permanent second contract; decide which at the moment you add it, not two years later. ## The tradeoff, stated honestly | | One canonical source | Canonical plus alias | |---|---|---| | Client reach | some clients blocked | awkward contexts served | | Readings that must agree | one | every layer must know the rule | | Failure mode | a client cannot call the endpoint | a check and the work use different values | | Cost of removal | none | a migration with unknown callers | The asymmetry is the point. Refusing an alias produces a **loud** failure — a client cannot call the endpoint, says so immediately, and the conversation happens before anything ships. Accepting one produces a **quiet** failure that appears later, under a specific combination of copies, in a layer nobody associated with the decision. A lead's job is to prefer loud failures at design time and reserve the quiet ones for cases with a named beneficiary. ## What to say when someone asks for the shortcut The productive answer is usually not "no" but "which client, and for how long". That reframes the request from a style preference into a migration with an owner, a metric and an end date. It also surfaces the cheaper alternatives that often satisfy the real need: a second route whose template carries the value in the canonical position, a small redirect or rewrite at the edge that maps the awkward form onto the canonical one before the service sees it, or a client library that hides the inconvenient source. Each keeps the service's own contract single-valued, which is the property the whole discipline exists to protect.

  • Why resolve an alias before the policy layers rather than inside the handler?
    Because the layers around the handler read the request themselves. If the folding happens inside the handler, the gateway rule, the audit log and the cache key still see two copies and each picks one, which is exactly the split reading the alias was supposed to be safe from. Normalising first leaves one value for everyone downstream.
  • What is the cheaper alternative when a client genuinely cannot send the canonical source?
    Move the translation out of the service: a second route whose template carries the value in the canonical position, or a rewrite at the edge that maps the awkward form onto the canonical one before the service sees it. Either keeps the service's contract single-valued and confines the compatibility shim to one place with a clear owner.
  • How do you decide an alias has served its purpose?
    By the usage metric you added when you introduced it. Once traffic through the alias is zero, or confined to callers you can contact, removal is a scheduled change rather than a gamble. Without that signal every removal is an argument from hope, which is why aliases with no measurement are effectively permanent.
  • Is a documented precedence rule an acceptable substitute for rejecting conflicts?
    For a low-stakes value, yes — a display preference resolved by a published rule costs little. For anything that authorises, identifies or prices, no: the client cannot see which copy the server used, and neither can an auditor afterwards, so the cheapest defensible outcome is 400 naming both sources.

saying these in an interview costs you the question

  • Accepting a credential from the query string for client convenience
  • Adding an alias with no named caller and no removal plan
  • Resolving the alias inside the handler, after policy layers have read the request
  • Preferring one copy silently when two sources disagree on an identifier
  • Treating a second accepted source as free because the code is short