In a partial-update request, how does a server tell clear the nickname from leave the nickname alone?
answer
- absence is already spoken for
- one syntax, two instructions, contradiction
- presence tracked beside the value
- wrapper presence, or an updated-paths list
- path list survives default-omitting encoders
basics
~20 sBy tracking presence separately from value. Absence means leave it alone; an explicit null, a wrapper whose presence is the signal, or a list of the field paths being updated means the sender touched the field and wants it cleared.
solid answer
~40 sA sparse update body reserves absence for *leave this alone*, so the clear instruction needs a second signal. The usual three are: send the field with an explicit `null`; wrap the value in a small object whose own presence means *this field was mentioned*; or send a separate list of the field paths the request intends to set, so the body's contents stop being the only evidence of intent. The list is the strongest of the three, because it works even for a field whose new value equals the type's default and would otherwise be omitted by the encoder. Whichever you pick, write it into the contract — if each reader invents its own reading of a missing key, the endpoint's behaviour becomes a function of which service handled the request.
code
json · 4 lines{
"nickname": null,
"displayName": "Ada"
}go deeper
Recall that a sparse update uses absence to mean leave alone, and that clearing therefore needs some other signal in the request. One named mechanism is enough at this level.
Explain at least two mechanisms and what each costs. Say why a sentinel value fails once that value becomes legal input, and what the encoding you are using can actually represent.
Show the failure you have seen: a clear that turned into a silence at a re-encoding hop, or a field set to its type's default that the encoder dropped. Say how you detected it.
Treat it as contract design. Decide which states the endpoint accepts at all, reject the rest at the boundary, and make sure every service on the path implements the same reading rather than each choosing one.
## The problem the endpoint has to solve A partial update exists so a client can change one thing without resending everything it knows. That gives absence a job: a field the client did not mention must be left as it is. The job is load-bearing — take it away and the client has to fetch the whole record, change one field and send it all back, which reintroduces lost updates whenever two clients do it at once. But the same endpoint also has to support *clear this field*. Setting a nickname to nothing is an ordinary user action. And if absence already means *leave alone*, omission cannot also mean *clear*: one syntax cannot carry two opposite instructions. ## The three mechanisms **Explicit null.** The body carries the key with a null literal. Absence means leave alone, null means clear, a value means set. This is cheap and reads naturally in a self-describing text encoding. Its limits: some encodings have no null value for a field unless the type opts into it, and any hop that decodes and re-encodes with a null-dropping writer turns the clear into a silence. **A wrapper whose presence is the signal.** Instead of a bare scalar, the field holds a small object with one value inside. The outer object being there means *the sender mentioned this field*; what is inside says what to set it to. Presence and content become two separate facts again. This is the standard answer in encodings that cannot carry a null scalar, and it costs a nesting level and a few bytes per field. **An explicit list of updated field paths.** The request carries, beside the record, a list naming exactly the fields it intends to set. The server applies only those, taking each value from the body. Now presence is stated rather than inferred, which means it survives an encoder that omits default-valued fields — the strongest property of the three. Its cost is that the list and the body can disagree, so the server must decide what a named-but-absent path means and say so in the contract. A fourth design exists — a request that is a list of edit operations rather than a sparse record — but that changes the message from *a partial record* into *a script of edits*, which is a different contract with different properties. ## Comparing them | Mechanism | Clears a field | Survives a default-omitting encoder | Extra cost | |---|---|---|---| | Explicit null | Yes, where the encoding admits null | No — a default value still vanishes | None | | Presence wrapper | Yes, by wrapping the cleared value | Yes — the wrapper itself is the signal | One nesting level per field | | Explicit path list | Yes, by naming the path | Yes — the list is independent of the body | Body and list can disagree | ## The rules that keep it honest 1. **Write the semantics of each state into the contract, per endpoint.** Absence, null, and empty each need a stated meaning. Anything the endpoint does not want should be rejected, not reinterpreted. 2. **Do not overload one syntax with two instructions.** If null means clear, it cannot also mean *the value is unknown*; if it must mean both, the record needs a second field that says which. 3. **Never reach for a sentinel that a user could type.** Using the empty string or `-1` to mean cleared works only until that value becomes legitimate input, and then it fails silently. 4. **Check the whole path, not just the endpoint.** Every hop that decodes and re-encodes can flatten the distinction. Presence must survive to the writer, not merely to the first reader. ## Why interviewers like this one It is the smallest realistic setting in which the three-state distinction stops being trivia. The candidate who only knows *null and absent are different* usually stalls at this question, because the next step is to choose a mechanism and defend it against the encoding that will actually carry the bytes. The candidate who has shipped one of these will volunteer the awkward parts unprompted: what happens to a field named in the path list but missing from the body, and what an intermediary does to an explicit null on the way through.
- Why is an explicit list of updated field paths stronger than relying on the body alone?Because it states presence instead of inferring it from the bytes. An encoder that omits any field equal to the type's default will drop a field the client genuinely set to zero or to the empty string, and the body then looks identical to one that never mentioned it. The path list is carried separately, so it still names the field, and the server applies it.
- What should the server do with a field named in the path list but missing from the body?Pick one reading and put it in the contract. The two defensible choices are to treat it as a clear, on the grounds that the sender named it and supplied no value, or to reject the request as malformed. What is not defensible is leaving it undefined, because each reader will then guess differently and the endpoint's behaviour will depend on which service handled it.
- Does using an explicit null for clear create a problem for a field that is legitimately nullable in the domain?Yes, if null already means something about the value, such as unknown. Then one literal is carrying two instructions and the request is ambiguous. The fix is to stop overloading it: track presence separately, so a field can be both mentioned and null-valued, with the two facts recorded independently.
saying these in an interview costs you the question
- Thinks omitting a field is how a sparse update asks for a clear
- Picks a sentinel value a user could legitimately type
- Assumes every encoding can carry a null scalar
- Forgets an intermediary may re-encode and drop nulls
- Leaves each reader to decide what a missing key means