DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Stop Guessing, Start Seeing: A Five -Layer Framework for Monitoring Distributed Systems
  • Building Regulated AI Systems at Scale: Frameworks for Effective Governance
  • From Hype to Harm: Why AI Governance Needs More Than Good Intentions
  • Building an AI-Powered Cold Email System With CrewAI

Trending

  • Detecting Bugs and Vulnerabilities in Java With SonarQube
  • Lambda-Driven API Design: Building Composable Node.js Endpoints With Functional Primitives
  • Ingesting Fixed-Width Mainframe Files Into Delta Lake: The Details Nobody Writes Down
  • Building Enterprise-Grade Real-Time IoT Dashboards with Vue 3, MQTT, and Kafka
  1. DZone
  2. Coding
  3. Frameworks
  4. The Update Problem REST Doesn't Solve

The Update Problem REST Doesn't Solve

Does your backend know the difference between {} and {"email": null}? It's vital if you want the correct data. Missing fields and explicit nulls carry different intent.

By 
Jan Nilsson user avatar
Jan Nilsson
·
May. 14, 26 · Analysis
Likes (1)
Comment
Save
Tweet
Share
3.5K Views

Join the DZone community and get the full member experience.

Join For Free

Consider the following two requests:  

JSON
 
{}  

and  

{ "email": null }


They look similar, but they are fundamentally different. In the first case, nothing is said about email; in the second case, email is explicitly set to null.

So, what should the system do? And how is that behavior defined today? Most systems cannot answer this precisely. They rely on conventions, mapping frameworks, or implicit behavior. 

This is not a limitation of JSON or JPA. It is the absence of a defined write model.

The Core Problem

A system that cannot distinguish between a field what was:

  • Not sent 
  • Sent with null 
  • Sent with a value 

does not have a well-defined way to update data. Without this distinction, the system must interpret the request. 

And interpretation introduces ambiguity. A missing field may:

  • Be ignored
  • Overwrite existing data
  • Be treated differently depending on the mapping layer 

None of this is visible in the API. The behavior exists, but it is not defined.

A Real Failure Scenario

Assume the current state is:

  • name = "Anna"
  • email = "[email protected]"

A client sends: {"name":"Anna"}

A common implementation looks like this:

Java
 
public void updateUser(UserDTO dto, User entity) {
	entity.setName(dto.getName());
	entity.setEmail(dto.getEmail());
 }


What happens to email?

  • If the mapper sets null → email is overwritten 
  • If the mapper ignores null → email is preserved 
  • If behavior changes later → the result changes 

The API does not define this. The framework does.

A refactoring, a new mapper, or a configuration change may alter the outcome without changing the request. This is not a client error; it is undefined behavior.

Common Approaches

Several approaches try to address partial updates:

  • Full updates (PUT): Require complete objects 
  • Partial updates (PATCH): Allow partial structures 
  • JSON merge patch: Merges values into existing state 
  • Mapping frameworks: Copy values into entities 

All of these operate on structure; none of them define intent. They describe what data looks like, not what the client meant.

A Simple Principle

To achieve correctness, the system must follow a simple rule: Only explicit intent may change state. If the client does not express intent, the system must not infer it.

This leads to three cases:

  • Field not present → no intent → no change 
  • Field present with value → update
  • Field present with null → clear

The distinction is not in the value itself, but in whether the field was present.

Making Intent Explicit

To implement this, the system must track presence per field.

A minimal example:

Java
 
public class UserDTO {
	private String email;
	private boolean emailPresent;

	public void setEmail(String email) {
		this.email = email;
		this.emailPresent = true;
	}
	public boolean isEmailPresent() {
		return emailPresent;
	}
	public String getEmail() {
		return email;
	}
 }


Now the backend can apply changes explicitly:

Java
 
public void updateUser(UserDTO dto, User entity) {
	if (dto.isEmailPresent()) {
		entity.setEmail(dto.getEmail());
	}
}


The behavior is now defined:

  • Not present → no change
  • Present null → clear
  • Present value → update

No interpretation is required.

Where It Breaks First

Booleans: {"active":false}

Is false an explicit value, or just a default? Without presence tracking, the system cannot tell.

Collections: {"roles":[]}

Does this mean:

  • Clear all roles
  • Or ignore roles

With explicit presence:

Java
 
if (dto.isRolesPresent()) {
	entity.getRoles().clear();
	entity.getRoles().addAll(dto.getRoles());
}


The meaning is clear:

  • omitted → no change
  • [] → clear
  • [x,y] → replace

These are not edge cases; they are normal updates.

Structural Consequence

The backend does not detect client mistakes. It cannot know whether a field was omitted intentionally or by accident. What reaches the backend is the only expressed intent.

The system can:

  • Validate values
  • Enforce invariants
  • Reject invalid states

But it must not guess missing intent. A system that treats missing data as instructions is making decisions on behalf of the client. 

This is where incorrect writes begin.

What This Solves

With explicit intent:

  • Missing fields never overwrite existing data 
  • Null values are consistently interpreted as clear 
  • Collections behave predictably
  • Updates are stable across refactoring and framework changes 

Most importantly:

The system no longer interprets requests; it executes them.

What This Does NOT Solve

This approach does not address:

  • Business validation
  • Concurrency control
  • Client-side errors
  • Default values

Those concerns remain in the domain and persistence layers. This pattern addresses only one problem: ambiguity in write intent.

Trade-Offs

This approach introduces additional structure. It requires:

  • Tracking presence per field or segment 
  • Explicit update logic in the backend 
  • More code than direct mapping

In other words, it adds boilerplate. But the trade-off is clear:

  • No implicit behavior
  • No ambiguity
  • No unintended data loss

Conclusion

There are multiple ways to interpret partial updates.

A system can:

  • Ignore missing fields
  • Reject incomplete requests
  • Apply defaults
  • Attempt to merge state

Each choice has consequences. This approach makes one decision explicit: The system does not guess what the client meant; it only acts on what is explicitly sent. If a field is missing, no intent was expressed, and without intent, nothing should change.

The question is not how your API handles updates; the question is whether that behavior is defined or left to chance.

JSON systems Framework

Opinions expressed by DZone contributors are their own.

Related

  • Stop Guessing, Start Seeing: A Five -Layer Framework for Monitoring Distributed Systems
  • Building Regulated AI Systems at Scale: Frameworks for Effective Governance
  • From Hype to Harm: Why AI Governance Needs More Than Good Intentions
  • Building an AI-Powered Cold Email System With CrewAI

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook