Handling null values correctly in REST APIs is fundamental to building reliable integrations, yet many developers struggle with the nuances between null, empty strings, and omitted fields. These distinctions matter because servers, databases, and client SDKs interpret each case differently, and getting it wrong can lead to data corruption or unexpected behavior.
This guide covers how to pass null values in JSON payloads, handle them across different HTTP contexts like query parameters and headers, and define nullable fields properly in OpenAPI specifications. You'll learn the practical differences between null semantics across programming languages, best practices for API design, and how tools like Stainless SDK generation can provide compile-time safety for nullable types.
Null, empty, and missing values compared
To pass a null value in a REST API, you should use the JSON literal null
in the request body for methods like POST, PUT, or PATCH. This explicitly tells the server that a value is absent. It is fundamentally different from an empty string (""
), which represents a present but empty text value, or an omitted field, which implies the client is not providing any information about that field.
Understanding the distinction is crucial because servers, databases, and client SDKs treat these cases differently.
null
value: The field is present, but its value is explicitly null. This often means "no value" or "unknown."{ "description": null }
Empty string: The field is present, and its value is a string of zero length. This is a valid string, not an absence of a value.
{ "description": "" }
Omitted field: The field is not included in the JSON object at all. This is useful for optional fields or in PATCH requests where you only send fields you want to change.
{}
A server might interpret an omitted description
as "do not change the description," while description: null
could mean "clear the description." This distinction gives you precise control over your API interactions.
Null value semantics in REST APIs
The null
you see in a JSON payload is a formal data type within the JSON specification, just like string
, number
, or boolean
. When your application serializes data to send to an API, your language's concept of null is converted into this JSON null
type.
This means Python's None
, Go's nil
, and Java's null
all become the same thing over the wire.
A common point of confusion, especially for frontend developers, is the difference between null
and undefined
in JavaScript. While both can represent the absence of a value, JSON.stringify()
treats them differently. A key with a null
value is preserved, while a key with an undefined
value is omitted from the resulting JSON string entirely.
Warning: Be careful not to send the string "null". This is a four-character string, not the JSON null
type, and will almost certainly cause validation errors or unexpected behavior on the server.
Pass null values in JSON payloads
Sending null
is most common in the body of POST, PUT, and PATCH requests. Here’s how you can do it in practice and how different languages handle the serialization.
Body payload examples
Using curl
, you can send a JSON payload with a null
value directly. This example sends a request to update a user's middle name to null
.
With a strongly-typed SDK, like one generated by the Stainless SDK generator, this becomes even simpler and safer. The SDK handles the JSON serialization for you, and the type system ensures you can't make a mistake.
Language serialization rules
Most standard libraries for handling JSON automatically convert the language's native null type into the JSON null
literal.
JavaScript:
JSON.stringify({ middle_name: null })
produces'{"middle_name":null}'
.Python:
json.dumps({'middle_name': None})
produces'{"middle_name": null}'
.Java (with Jackson): Serializing an object where a field is set to
null
will correctly write it asnull
in the JSON output.
Multipart form data constraints
Passing a true null
value in a multipart/form-data
request is not natively supported. Multipart requests are designed to send a series of key-value pairs, where values are typically strings or file data.
Common workarounds include:
Omitting the field entirely if the server is designed to interpret its absence as a no-op.
Sending the field with an empty string value (
middle_name=
) and having the server logic interpret an empty string asnull
. This requires clear API documentation.
Handle null values across scenarios
While JSON bodies are the most common place to see null
, the concept of "no value" appears in other parts of an API call. Here’s how it's handled in different contexts.
Query parameters and URLs
There is no official standard for representing null
in a URL query string. The most common and recommended approach is to simply omit the parameter. If a user's status
is null, you would make a request to /users
instead of trying to represent null in /users?status=null
.
Another pattern is to send the parameter with an empty value, like /users?status=
. This requires the server to be explicitly coded to interpret an empty status
parameter as a filter for null statuses.
Request headers limitations
HTTP headers are key-value strings. Similar to query parameters, you cannot send a "null" value. The contract for optional headers is based on their presence or absence. If you don't need to send an X-Customer-ID
header, you just don't include it in the request.
HTTP method semantics
The meaning of null
can be tied to the HTTP method being used.
GET: A response to a GET request can contain fields with
null
values, indicating that data for those fields does not exist.PATCH: This is a primary use case for
null
. Sending{ "middle_name": null }
is a clear instruction to the server to clear the value of themiddle_name
field.DELETE: A successful DELETE request often returns a 204 No Content response with an empty body, which is conceptually similar to null.
Arrays and nested objects
JSON null
can be used anywhere a value is expected, including inside arrays and as the value for a nested object.
In an array:
{ "tag_ids": [101, null, 105] }
could signify that the middle tag is unassigned.As an object value:
{ "user": { "address": null } }
clearly indicates the user has no address on file.
Specify null behaviour in OpenAPI specs
For API producers who create OpenAPI specs, clearly defining which fields can be null
is essential for a good developer experience. The OpenAPI specification provides a standard way to do this, which tools like Stainless use to generate high-quality, type-safe SDKs.
Nullable flag in OpenAPI 3.0
In OpenAPI 3.0, you can indicate that a field can be null
by adding nullable: true
to its schema definition.
Union syntax in OpenAPI 3.1
OpenAPI 3.1 aligns more closely with the JSON Schema standard and uses a type array to represent a union of types. This is the more modern and explicit way to define a nullable field.
Stainless SDK generation impact
When you define fields as nullable in your OpenAPI spec, code generation tools can create much safer and more ergonomic SDKs. For example, Stainless reads your spec and generates corresponding nullable types in each language.
TypeScript: A field defined as
type: [string, "null"]
becomesmiddle_name: string | null;
. This provides compile-time safety, preventing developers from accidentally treating a potentially null value as if it were always a string, which eliminates a whole class of runtime errors. Remember that your API isn't finished until the SDK ships with this level of type safety built in.Python: The same field becomes
middle_name: Optional[str]
.
This provides compile-time safety, preventing developers from accidentally treating a potentially null value as if it were always a string, which eliminates a whole class of runtime errors.
Required versus optional fields
A field can be both required
and nullable
. This means the key must always be present in the JSON object, but its value is allowed to be null
. This is different from an optional field, where the key itself can be omitted.
Apply best practices for null values
Handling null
consistently and predictably is a hallmark of a well-designed API. Here are some best practices to follow.
Be explicit. Use
null
to explicitly clear a field's value. For optional data that isn't being provided, prefer omitting the field from the payload.Avoid ambiguity. Never use an empty string (
""
) as a stand-in fornull
. An empty string is a valid value, whereasnull
signifies the absence of one.Document everything. Your API reference should clearly state which fields are nullable and how the server interprets
null
values for each endpoint, especially for PATCH operations. You should also integrate SDK snippets with your API docs to help developers understand exactly how to handle these nullable fields in their code.Test your null paths. Your automated tests should include cases for sending
null
values to ensure the server behaves as expected.Leverage tooling. Use tools that can analyze your OpenAPI spec for inconsistencies. For instance, Stainless provides diagnostics that can flag issues with how nullable fields are defined and used, helping you maintain a robust API contract.
Frequently asked questions about null values in REST APIs
Here are answers to some common questions developers have about handling null
in REST APIs.
How do I pass a null query parameter?
You can't pass a true null
. The best practice is to omit the parameter entirely, but some APIs use a convention where an empty parameter (e.g., ?status=
) is interpreted as a filter for null values.
How do I clear a field with JSON Patch?
You can use the "replace" operation with a null
value. For a field named middle_name
, the JSON Patch operation would be { "op": "replace", "path": "/middle_name", "value": null }
.
How do I validate nullable fields in popular frameworks?
Most modern validation libraries have built-in support for nullable types. For example, in Python's Pydantic, you'd define a field as middle_name: Optional[str] = None
.
How do Stainless SDKs represent nullable types?
Stainless generates idiomatic nullable types for each language, such as string | null
in TypeScript, Optional[str]
in Python, *string
(a pointer to a string) in Go, and Optional<String>
in Java.
Does using null break backward compatibility?
Adding a new nullable field to a response is generally a non-breaking change. However, changing an existing, non-nullable field to be nullable can be a breaking change for clients that are not prepared to handle null
. Making Java nullable fields backwards compatible requires careful consideration of these constraints.