AlgoMaster Logo

Partial Updates and Field Masks

Medium Priority15 min readUpdated September 13, 2026
Listen to this chapter
Unlock Audio

Updating just a few settings sounds simple until a meaningful value looks like an omitted one. For example, a customer might turn off email notifications and set a daily notification limit to zero. Both values are intentional, but a client library that drops false or zero values can accidentally turn the request into “change nothing.” A nested settings object introduces another question: does changing one setting preserve its siblings?

Partial updates need a precise way to express intent.

This chapter explains field presence, update masks, clearing values, nested paths, collections, validation, and compatibility. The examples use a fictional bookstore's customer notification settings over HTTPS.

1. Field Presence and Update Intent

A partial update changes selected parts of a resource while preserving the rest. The difficult part is defining how the request selects those parts.

A presence-based contract treats fields the client supplies in a payload as instructions. An operation-based patch lists actions such as assigning or removing values. A field mask names the fields an operation applies to, separately from the object carrying their new values.

Each approach needs explicit semantics. JSON Merge Patch uses object-member presence and gives null a removal meaning. JSON Patch provides an operation document with paths. A mask-based API instead combines a set of selected paths with proposed values. These are different contracts, not interchangeable JSON shapes.

The distinction matters when a serializer uses default values. A request object may contain false because the caller explicitly selected it or because an unset Boolean received its language default. Without field-presence tracking or another expression of intent, those cases can become indistinguishable.

An update mask solves the selection problem: selecting email.enabled says that this field is part of the edit. The value still needs a documented interpretation. A mask does not automatically decide whether an omitted selected value means reset, removal, or error.

Do not detect updates with truthiness checks such as “apply this field if its value is true.” False, zero, empty strings, and empty arrays can all be valid requested values.

2. A Mask-Based Request Contract

The bookstore stores optional-notification settings at /customers/cust_42/notification-settings. Assume the customer's current representation is:

email.enabled is a Boolean. email.digest_hour is an integer from 0 through 23, which the service interprets in UTC. daily_limit is an integer from 0 through 20; zero allows no optional notifications. These preferences do not suppress mandatory account or security messages.

digest_title is either null or a string of at most 80 Unicode code points. Null selects the service's default heading; an empty string deliberately suppresses the heading. topics contains distinct values from orders and recommendations; an empty array selects no optional topics. All four top-level fields remain present in the stored representation.

This endpoint defines a custom JSON patch body with two required members: settings, an object carrying values, and update_mask, an array of field paths. It uses PATCH with application/json under this documented application contract. This is neither JSON Merge Patch nor the Protocol Buffers JSON encoding of FieldMask.

The mask contains case-sensitive paths relative to the settings resource. For example, email.enabled selects the Boolean inside email. It is not settings.email.enabled, because settings belongs to the request envelope rather than the resource.

The diagram shows how the service combines the three inputs:

The service does not write known writable values outside the mask. The API still type-checks supplied values and rejects unknown or read-only fields, but it derives the proposed saved state only from selected assignments. Domain rules then apply to that proposed state.

This separation lets a client send a larger settings object without treating every value in it as an intended edit. The client must still build the mask from the user's actual changes.

3. Selected Values and Preserved Fields

Assume an authorized GET returned the initial settings with strong entity tag "notifications-42-v3". The customer turns off email and sets the daily limit to zero:

The mask does not select the supplied digest_hour value. Even if it came from a stale form, it does not change the saved hour:

The service has saved false and zero. The digest hour, title, and topics remain unchanged. Disabling email preserves the hour so the customer can re-enable it without rebuilding its configuration.

The update mask controls writes, not which fields appear in the response. This API returns the complete representation the caller may read, including fields outside the mask. A response field selector, if the API offers one, would be a separate contract.

Each HTTP JSON body occupies one line without a trailing newline. Credentials are placeholders. Each complete request example in this chapter is an independent scenario starting from the initial settings and tag, rather than a continuation of the preceding example.

4. Clearing and Resetting Values

Define the interaction between selection and value presence before implementing the request parser. This API requires a value for every selected path, including an explicit null when null is the intended value.

Selection and supplied valueBehavior in this API
Mask does not select the fieldPreserve its saved value
Selected Boolean with falseAssign false
Selected integer with 0Assign zero, subject to its range
Selected digest_title with ""Suppress the heading
Selected digest_title with nullUse the service's default heading
Selected topics with []Clear all optional topic selections
Selected field absent from settingsReject with a missing-value error
Selected non-nullable field with nullReject with a validation error

These rules are application choices. Other mask-based APIs may reset a selected field when the client omits its value. Clients must follow the particular endpoint's contract rather than assume that all field masks imply one reset rule.

The customer can restore the default heading and clear topic selections explicitly:

The saved representation is:

The title field remains present with a null value. That differs from the removal meaning of null in JSON Merge Patch. Do not label this request application/merge-patch+json: its envelope and reset behavior follow a different contract.

Client serialization must preserve selected values. If a serializer drops false, 0, or [], this API rejects the resulting missing assignment rather than guessing the caller's intent. Avoid filling missing update values with creation defaults during decoding.

5. Nested Fields and Parent Selection

A mask path can select a leaf value or, when the API permits it, a whole nested object. Their scopes differ.

This API accepts email.enabled and email.digest_hour as leaf paths. Selecting either preserves the other. It also accepts email as a whole-object replacement, which requires both enabled and digest_hour in the supplied object.

For example, the following request body changes only the enabled flag:

Selecting the parent instead requires a complete email object:

That second body intentionally changes both values. The diagram makes the scope visible:

Whole-object replacement is this API's parent-path rule. Some implementations merge selected objects instead. Define the behavior explicitly; accepting dotted paths does not establish it.

The API rejects overlapping paths such as email and email.enabled in one mask. It also rejects duplicate paths. These choices remove questions about order and precedence: the mask is a set of selected locations, not an ordered program.

The email object always exists in this schema. In an API with optional nested objects, specify whether a leaf update can create a missing parent. Do not let an object-mapping library decide whether siblings receive defaults or disappear.

6. Arrays, Maps, and Path Syntax

Collection-valued fields need a separate assignment rule. This API treats selected topics as replacement of the complete array. It does not append entries, merge them by value, or interpret array positions as identities. The service stores the submitted order and rejects duplicates or unsupported topic names.

The accepted mask paths are exactly email, email.enabled, email.digest_hour, daily_limit, digest_title, and topics. Paths such as topics.0, topics.*, or /email/enabled are invalid. The last example resembles JSON Pointer syntax, but this contract uses dot-separated field names.

Index-based edits are fragile when other writers can insert or remove elements. If a collection contains independently editable entities, give them stable identifiers and consider individual resource operations. Replacing a two-element preference array is different from editing one item in a large shared reading list.

Maps introduce another ambiguity: a dot can separate schema fields or belong to a user-defined map key. An API supporting map-key selection needs a documented escaping grammar and rules for assignment and removal. Do not add arbitrary map-key paths to a dot parser without defining those cases. This settings contract has no map-key selection.

The API requires a nonempty mask and rejects *. An absent mask or empty array produces 400 Bad Request; it never means “update everything.” Rejecting wildcard selection also prevents an older client from accidentally selecting fields the API added after developers wrote that client. These policies differ across API families, so document yours.

7. Validation, Authorization, and Application

Treat mask paths as untrusted input. Resolve them against the public writable schema, not arbitrary object attributes or database column names. Validate the envelope, paths, supplied types, selected values, permissions, and resulting resource before committing.

A typo must not silently turn a requested edit into a successful no-op:

The service reports the invalid selection:

This API uses 400 for malformed mask structure, unknown paths, duplicates, and overlaps. It uses 422 Unprocessable Content for selected values that are missing or violate the settings rules. Neither failure changes the resource. The error envelope and codes are application-defined.

A valid path is not permission. Suppose a support user may inspect settings but cannot change them:

The service checks that the path's customer is accessible to the authenticated caller. A different customer who may not know these settings exist receives a generic 404 under the concealment policy. Neither ownership nor authority comes from values in the body.

For a parent selection, authorize every field it can change or clear. Checking permission on email while ignoring restrictions on its children can create a bypass. Never silently discard an unauthorized selected path and apply the rest.

The diagram summarizes application after the service establishes the caller's access to the target:

All selected changes form one patch and succeed or fail together. A mask narrows writes; it does not narrow validation of business rules involving other saved fields. For example, changing one boundary of a delivery window must still produce a valid window.

The example requires If-Match and rejects a stale version with 412. Coordinate the version check and commit: if another write makes the checked version stale, the update must fail instead of committing against that stale version. A mask does not stop two callers from editing the same field. Selecting only a few fields also does not let an update ignore a version check that covers the whole resource.

8. Standard Types and Compatibility

Field masks are a general design technique, but ecosystems define particular encodings and rules. Protocol Buffers provides google.protobuf.FieldMask, which stores paths as strings. Its JSON encoding is a single comma-separated string with lower-camel-case path components.

For example, JSON encoding represents protobuf paths email.digest_hour and daily_limit as "email.digestHour,dailyLimit". That is different from this chapter's custom update_mask array with snake-case paths. Use the standard type's encoding when working with protobuf-based tooling rather than substituting the illustrative JSON format.

Protocol Buffers field-presence rules also affect resets. With implicit scalar presence, an unset field and its default value can be indistinguishable in the generated API. Explicit presence tells you whether the caller supplied a value. An update mask selects which fields to update. These solve related but different problems. Design and test their interaction in the actual serialization stack.

Google's API guidelines prescribe their own update-mask behavior, including inferred selection when the client omits the mask and a wildcard for replacement. Those are conventions for that API family, not HTTP-wide requirements. Do not combine its path syntax with a different reset or omission policy and assume clients will infer the differences.

Explicit leaf masks help older clients preserve fields they do not know. Broad parent replacement can still remove or reset newly introduced children, even if the mask does not contain a wildcard. Review schema changes against both leaf and parent-selection behavior.

Generate masks from the fields the caller intended to edit. Building a mask from every property in a serialized response can select default-filled or stale values and undo the benefit of partial updates. Client libraries should make it straightforward to send selected false, zero, empty, and null values without accidentally broadening the edit.

Keep paths stable as part of the public contract. Renaming a JSON field can also break saved masks, client code, and request builders. A field mask is useful only when its selection and value rules remain predictable as the resource evolves.

Summary

Partial updates need separate answers for which fields change and what values they receive. Field masks make selection explicit, but the API must still define missing values, clearing, nested objects, and collection assignments.

Validate paths against the writable schema, authorize every selected effect, and apply the complete update atomically. Use precise masks and documented serialization rules so default values and future fields do not turn a focused edit into an unintended replacement.