Representative interview topic

Backend interview: How would you design evolvable HTTP Structured Fields?

BackendHard
Offer.cc Editorial TeamPublished Updated

Question

You need to add an HTTP response field carrying capabilities and parameters to a public API. How would you use Structured Fields to define the syntax, handle duplicate fields and invalid input, and keep old clients safe?

Prompt and scope

A public API needs a Features response field containing capability names, priorities, and experiment parameters. Clients, CDNs, gateways, and SDKs in several languages will read it; legacy clients can only ignore unknown fields. Design the field format, serialization and parsing rules, compatibility policy, and verification plan.

This is a backend API-contract question. The key is turning a “string-like header” into an interoperable protocol. RFC 8941 defines the common Item, List, Dictionary, and parameter model, and RFC 9651 is its revision. RFC 9110 requires new fields to specify their grammar and reject dangerous control characters. You do not need to implement every RFC algorithm, but you must define the boundaries.

What the interviewer is testing

The interviewer wants to see whether you define semantics before choosing List, Dictionary, or Item instead of concatenating comma-separated text. A strong answer covers sender serialization, recipient parsing, unknown members, duplicate-field combination, size limits, and telemetry.

A weak answer shows one sample value. A strong answer explains why a capability set is a Dictionary, why parameter keys are lowercase, why arbitrary non-ASCII text should not be hidden in a String, and how a parse failure avoids accidentally enabling a feature. Current backend API interview guides also emphasize stable contracts, backward compatibility, and failure modes.

Questions to clarify first

Field semantics and trust boundary

Confirm whether this is a hint, authorization decision, or business fact. If it affects permission, billing, or security, the server remains authoritative and must not trust a client echo. Ask whether the field may be cached and whether its value varies by user.

Type and compatibility envelope

Ask whether the value is an unordered capability set, an ordered priority list, or one version identifier. Confirm whether old clients must continue working, whether new parameters may appear, and whether gateways combine duplicate field lines. Those answers determine the container type and unknown-member policy.

Failure and resource budgets

Decide whether invalid input causes the whole field, one member, or the response to be ignored. Set byte, member, nesting, and parsing-time limits; these choices become part of the DoS boundary.

30-second answer framework

“I would define this as a versionable machine contract, not JSON hidden in a string. A capability set uses a Dictionary, with each key carrying a boolean or parameterized Item; keys and parameters follow the RFC serialization rules, and unknown members are ignored. The server emits restricted ASCII and enforces total-size and member limits. Recipients use the same grammar, treat invalid syntax as field absence, and never infer that a feature is enabled. I would test duplicate-field combination and cache variation at the gateway, shadow-parse first, and compare parse failures, field size, and accidental feature enables before rollout.”

Step-by-step solution

Step 1: Model the value before choosing a container

Use a Dictionary for capability switches, such as search;v=2, upload=?1. Use a List when each member has meaningful order or parameters. Use an Item for one version or policy name. Do not put JSON inside a header merely for convenience: intermediaries and SDKs still need a bespoke parser.

Step 2: Define an extensible field

Define keys such as search and upload; parameters such as v=2 and tier="pro" use only types allowed by the structured-field grammar. Parameter keys are lowercase. Keep display text outside the field, or use an explicitly supported Display String extension after checking every intermediary. Document each member’s semantics, default, and invalid-value consequence.

http
Features: search;v=2, upload=?1

Serialization should be deterministic so equivalent values do not produce needless cache-key or signature differences. Recipients must not replace a grammar-aware parser with split(','); commas, parentheses, quotes, and parameters have defined boundaries.

Step 3: Specify duplicate fields and unknown members

First state whether repeated lines are allowed. If the field is a Dictionary, middleware may combine lines, so the contract must define the combined meaning and a conflict rule for duplicate keys. Ignore unknown keys and optional parameters by default. For a known key with an invalid type, either drop that member or the complete field, but make the choice normative. A security switch must never become enabled because parsing failed.

Step 4: Build a strict but usable parsing boundary

Limit total bytes, members, nesting depth, and CPU time before deep parsing. Reject CR, LF, NUL, and other characters outside the field grammar. External input does not require constant-time parsing, but exception paths must not repeatedly parse a huge value. Record categorized failures without logging the full potentially sensitive field.

Step 5: Handle caching, signatures, and evolution

If the field varies by user or experiment cohort, use the correct Vary response behavior or private caching; otherwise a CDN can expose one user’s capabilities to another. If the field is covered by HTTP Message Signatures, signers and verifiers need the same canonical structured value. Additive keys and optional parameters should remain ignorable to old clients; removing or changing semantics requires a version or migration window.

Step 6: Prove the design with rollout and counterexamples

Shadow-parse first without changing behavior, then enable a small internal cohort. Test duplicate keys, empty lists, broken quotes, unknown parameters, oversized fields, proxy combination, and cache mismatches. Compare parse success, accidental enables, response bytes, CPU, cache hits, and SDK versions with and without the field. Every parse failure returns to the safe default.

High-quality sample answer

I would treat this as a protocol-design problem. First I would confirm whether the field is only a capability hint; if it controls authorization, the server remains authoritative. For a capability set I would choose a Structured Field Dictionary and define each key as a boolean or parameterized Item. I would not use a List for unordered capabilities. The contract would specify serialization, parameter types, duplicate lines, unknown members, and invalid-value consequences.

The sender emits restricted ASCII and enforces field-size and member limits. The recipient uses an RFC-compatible parser rather than splitting on commas, rejects control characters, ignores unknown keys, and treats a known key with the wrong type as absent. The gateway has one fixed duplicate-combination rule, never an accidental “last value wins.”

I would also review cache and signature behavior: user-specific capabilities require Vary, private caching, or no caching, and both sides of a signature must normalize the value identically. I would shadow-parse, then canary the field while monitoring parse failures, accidental enables, size, and CPU. Old clients continue ignoring the field; only clients that explicitly support the version enable the new behavior.

Common mistakes

  • Putting JSON in a string header → Proxies and SDKs still need custom parsing, with inconsistent escaping and duplicate semantics → Use the RFC Item, List, or Dictionary model and document member meaning.
  • Parsing with split(',') Quotes, inner lists, and parameter delimiters are cut incorrectly → Use a grammar-aware parser and invalid-syntax tests.
  • Failing on every unknown parameter → New senders cannot interoperate with old clients → Ignore extension parameters unless a known safety constraint fails.
  • Enabling a feature after parse failure → Truncation or intermediary manipulation can turn into an accidental experiment or privilege → Return to a safe default and record a categorized failure.
  • Ignoring cache variation → A CDN can reuse personalized capabilities for another user → Set Vary, use private caching, or do not cache the response.

Follow-up questions and responses

Follow-up 1: Why not put this in response JSON?

JSON may be better when the capability is only business data in the body. Structured Fields are useful when HTTP metadata, gateways, and cache policy need to inspect the value before consuming the body. Do not give both representations independent authority; if both exist, define precedence and detect disagreement.

Follow-up 2: What if several proxies combine the field?

Specify whether repeated lines are valid and normalize them into one parser input at a trusted boundary. For a Dictionary, reject duplicate keys or define an explicit conflict rule; do not rely on whichever value happens to be last. Integration tests should cover HTTP/1.1 repeated lines, HTTP/2 field representation, and the real CDN path.

Follow-up 3: What if a new parameter needs non-ASCII text?

Do not place UTF-8 directly in a String type that is limited by the chosen grammar. Define and verify a supported Display String extension, or keep display text in the body and carry a stable identifier in the field. Enable it only after every intermediary and SDK supports the type.

Follow-up 4: The parser causes a CPU spike. What do you do?

Immediately tighten byte, member, nesting, and parameter-count limits and treat over-limit fields as absent. Keep an input hash and failure category for diagnosis, not the complete value. Moving parsing to a constrained worker can reduce blast radius, but it cannot replace grammar limits and a canary rollback.

Public sources

Related questions