Spots

PATCH vs. "Drop Null Properties": Two Google-Style Ways to Clear a Field

If your API drops null properties from its JSON, PATCH can no longer tell "clear this field" apart from "leave it alone." In this post, I'll show two ways I've solved that while still following Google's API guidelines. When designing APIs, I often refer to Google's AIPs (API Improvement Proposals) and Style Guides. The Google JSON Style Guide has a rule that says to "consider removing properties with null values." In other words, for a Users resource with name and age, if age is unset (NULL), the recommended JSON looks like this: Adopting this rule, however, creates a problem when implementing PATCH (partial updates). Yes, the "drop nulls" rule and PATCH can coexist (or so I believe).

The rule is a recommendation ("consider removing"), and

The rule is a recommendation ("consider removing"), and it explicitly allows an exception when there's a strong semantic reason to keep the property. You could argue that wanting to clear a value is exactly that kind of reason. But then every client has to send null on purpose, and the rule stops being a rule.

If clients also omit nulls in their requests

If clients also omit nulls in their requests (the rule applies to requests too), the server can no longer distinguish "not specified" from "clear this value." So the intent has to travel through a different channel. These are the two channels I've used: Approach 1: Turn "unset" into a value (enum zero value, AIP-126). Good for enum fields. Approach 2: Explicitly list the fields to update (update_mask, AIP-134). Works for any type. The "Empty/Null Property Values" rule The Google JSON Style Guide has a rule called Empty/Null Property Values.

Consider removing empty or null values. If a

Consider removing empty or null values. If a property is optional or has an empty or null value, consider dropping the property from the JSON, unless there's a strong semantic reason for its existence. { "volume": 10, // Even though the "balance" property's value is zero, it should be left in, // since "0" signifies "even balance" (the value could be "-1" for left // balance and "+1" for right balance. "balance": 0, // The "currentlyPlaying" property can be left out since it is null. // "currentlyPlaying": null } Consider removing empty or null values.

If a property is optional or has an

If a property is optional or has an empty or null value, consider dropping the property from the JSON, unless there's a strong semantic reason for its existence. Note: The comments in the quote are for illustration only; JSON doesn't actually allow comments.

In short: "Unless there's a particular reason, remove

In short: "Unless there's a particular reason, remove empty or NULL properties from the JSON." In the example above, balance can be -1 or 1, so 0 carries meaning. My reading is that this is why it's kept rather than omitted.

The rule applies to both requests and responses

The rule applies to both requests and responses. The idea is to keep a property only when there's a strong reason (i.e., the value carries meaning).

Any policy would work, but with strictly typed

Any policy would work, but with strictly typed languages becoming more common, it's nice to have a rule like this in place. You don't have to agonize over undefined vs. null... until PATCH shows up. The PATCH HTTP method applies partial modifications to a resource. PATCH request method - MDN The PATCH HTTP method applies partial modifications to a resource.

PUT replaces the whole resource; PATCH changes only

PUT replaces the whole resource; PATCH changes only part of it. Whether a PATCH is idempotent depends on its design. Both approaches in this post only set values, so their requests stay idempotent and safe to retry. Here's a side-by-side comparison: Wait, we can't clear age? Some of you may have noticed already: with PATCH, clearing age turns out to be a problem. Say the resource is currently in this state: Then a thought crosses your mind: "Hmm, I'd rather take my age off my profile." Under the rule, sending "age": null isn't an option, so omitting it is all the client can do: But the server reads this as "A PATCH request came in. So this is a request to update name." The result: Once a value has been entered, there's no way to clear it. To sum up, a PATCH body inherently has three states:

The rule of omitting NULLs erases the distinction

The rule of omitting NULLs erases the distinction between "clear it" and "leave it alone." That's the root of the problem. In TypeScript terms, it's the difference between age?: number and age?: number | null. Strictly typed languages like TypeScript and Go make you want to keep those three states apart.

News

PATCH vs. "Drop Null Properties": Two Google-Style Ways to Clear a Field

If your API drops null properties from its JSON, PATCH can no longer tell "clear this field" apart from "leave it alone." In this post, I'll show two ways I've solved that while still following Google's API guidelines.

@spots #dev
Source: Dev.to
See more like this