DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
World desk5 min

Handling Omitted vs. Null JSON Fields in Go PATCH Requests with Gin

A Go pointer alone cannot tell whether a PATCH field was omitted or sent as null. Choose clear semantics, track presence explicitly, and validate the full proposed resource before saving.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a PATCH endpoint, treat a field as having three possible inputs: omitted, explicitly null, or present with a value. JSON has no undefined literal; developers often use “undefined” to mean that an object member was omitted. A normal Go struct field—including a pointer—does not preserve all three states after ordinary JSON decoding. Choose the endpoint’s patch semantics first, represent field presence explicitly, validate the proposed resource, and persist the change only after the whole update passes.

Why a pointer does not distinguish omitted from null

JSON objects may omit a member or include it with the value null. Those inputs can mean different things in an update: omission commonly means “leave unchanged,” while null may mean “clear this value.” JSON itself does not have an undefined value. The Go encoding/json package’s ordinary unmarshalling does not retain a separate omitted-field marker for a struct field; for a pointer field, both an omitted member and explicit null leave the pointer nil. See the Go encoding/json documentation.

As an Amazon Associate I earn from qualifying purchases.

That creates a practical problem: a handler cannot infer whether nil means “the client said null” or “the client sent nothing.” Likewise, decoding into a non-pointer field can make an omitted field indistinguishable from a supplied zero value. For PATCH, that matters for legitimate updates such as setting enabled to false, quota to 0, or label to an empty string.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the patch format and null behavior

Before writing the Gin handler, specify what omission and null mean for each field. If interoperability is important, consider one of the established patch media types instead of an application-defined object format.

Format Request shape Omission Clearing or removing Useful when
Custom presence-aware object Resource-like JSON object with application-defined rules Define as unchanged Define null behavior per field You need flexible, endpoint-specific rules and will document them consistently.
JSON Merge Patch (RFC 7396) Resource-like patch object Unchanged null removes the corresponding target member A compact object merge is a natural fit. See RFC 7396.
JSON Patch (RFC 6902) Array of operation objects No operation means unchanged Use an explicit remove operation Clients need explicit path-level operations such as add, replace, remove, or test. See RFC 6902.

These formats are not interchangeable. RFC 7396 gives null a removal meaning; RFC 6902 expresses removal as an operation. An ad hoc DTO with custom null rules is neither standard unless it implements the corresponding format and semantics. RFC 7396 states: “Null values in the merge patch are given special meaning to indicate the removal of existing values in the target.”

Represent presence for a custom PATCH object

For a small endpoint with custom semantics, a wrapper can record whether a member appeared, whether its value was null, and—if it was not null—the decoded value:

type PatchField[T any] struct {
    Present bool
    Null    bool
    Value   T
}

func (p *PatchField[T]) UnmarshalJSON(data []byte) error {
    p.Present = true
    if bytes.Equal(bytes.TrimSpace(data), []byte("null")) {
        p.Null = true
        return nil
    }
    return json.Unmarshal(data, &p.Value)
}

type UpdateUserRequest struct {
    Nickname PatchField[string] `json:"nickname"`
}

This is an illustrative sketch, not a complete endpoint. It needs the appropriate imports and application-specific rules. A present member invokes the wrapper’s UnmarshalJSON; an absent member leaves the wrapper at its zero value. With that representation, the handler can distinguish omission from null and from a supplied value. Decide how the wrapper should behave for nested objects, arrays, duplicate keys, and marshaling before treating it as a reusable general-purpose type.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Another option is decoding the request object into map[string]json.RawMessage. A missing map key indicates omission; for a present key, inspect the raw JSON for null or decode it into the expected type. This makes field-name mapping and type checks explicit, but the handler must deliberately handle known and unknown JSON names.

Bind JSON in Gin without losing control of errors

Gin’s JSON binding parses request data, while the patch logic decides what each input means. When the handler needs to choose its own error response, use ShouldBindJSON and handle the returned error. Gin’s must-bind methods abort the request and write an HTTP 400 response on binding errors, so do not accidentally write a second response afterward. Gin documents request binding and validation in Request Binding & Validation.

Gin integrates with go-playground/validator/v10 for validation. For a presence-aware wrapper, make sure the JSON binding path uses the wrapper’s encoding/json unmarshalling behavior as intended. Gin’s documentation about binding a custom unmarshaler also discusses TextUnmarshaler in supported URI and form scenarios; that is not, by itself, a general solution for omitted-versus-null JSON members.

Validate the patch and the resulting resource

Validation has two jobs here. First, check supplied non-null values against their field rules. Second, check business invariants against the complete resource after applying the patch. A PATCH request is partial, so a field that was omitted should not fail merely because it is absent from the request. Null also needs an explicit policy: allow it only for fields the API considers clearable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Do not blindly use a required tag on every PATCH field. Validator’s required semantics generally demand a non-zero or non-nil value, which can reject valid assignments such as false, 0, or an empty string, as well as fields omitted intentionally.
  • Run field validation only when a field is supplied with a value, unless the endpoint explicitly defines validation for null or absence.
  • Use validator’s partial-validation or struct-level facilities where they fit; they do not infer omitted-versus-null meaning for an ordinary struct. See the validator/v10 documentation.
  • Apply proposed changes to a copy or newly built resource, then validate cross-field and business constraints against that complete proposed state.

For example, if an update changes a minimum and maximum together, checking each field in isolation may miss that the resulting minimum exceeds the maximum. Validate the proposed pair before saving either change.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Apply and persist a PATCH atomically

Do not mutate a persisted model as fields are decoded or validated one by one. Decode the request, interpret presence, apply permitted changes to a copy of the current resource, validate the resulting state, and persist the update as one safe operation or transaction. This order avoids saving a partial update when a later field or invariant fails.

  1. Load the current resource.
  2. Decode and validate the request’s syntax and types.
  3. For each known field, leave it unchanged when omitted; apply a supplied value; and either clear it or reject null according to the endpoint contract.
  4. Validate field rules for supplied values and business constraints on the proposed complete resource.
  5. Save the proposed resource atomically; if validation fails, do not persist any part of the patch.

Cases your handler should get right

  • {} leaves every field unchanged.
  • {"nickname":null} clears the nickname only if the contract declares it clearable; otherwise reject it.
  • {"enabled":false} sets the value to false rather than treating it as omission.
  • {"quota":0} sets zero when zero is permitted.
  • {"label":""} preserves the difference between a supplied empty string and an omitted member.
  • Malformed JSON and unknown fields have deliberate, documented error behavior.
  • A patch that violates a cross-field invariant fails without persisting only some of its changes.

These cases are useful as endpoint tests because they exercise the distinct input states and the all-or-nothing update behavior.

Further Gin and Go references

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.