Data format interoperability means that independent producers and consumers can exchange data with an agreed interpretation. Sharing a syntax is one part of that agreement; character encoding, supported values and handling of ambiguous inputs also matter. Serialization and deserialization must preserve the distinctions the application needs.[ref]
Consider the original JSON input {"mode":"fast","mode":"safe"}. RFC8259 says object member names should be unique and warns that duplicate-name handling differs. In Python, the default json.loads result is {'mode': 'safe'}. The same decoder with object_pairs_hook=list instead returns [('mode', 'fast'), ('mode', 'safe')], preserving both pairs.[ref][ref]
The text has not changed, yet one consumer retains one value and another retains both occurrences. Re-encoding the default dictionary cannot recover the discarded occurrence. A consumer can instead use a hook that rejects a repeated name, making the ambiguity explicit before the application acts on it.
An exchange contract can therefore require unique names and a shared duplicate-rejection policy, as well as a character encoding such as UTF-8. That is a stronger agreement than merely saying that both programs support JSON. Data validation then checks application-level requirements on the agreed decoded representation.
Data validation 2026-11-05
Data validation checks a value against stated requirements, such as an allowed data type, range or relationship between fields. Parsing establishes how input fits a syntax; an application's validation rules determine whether the resulting value is suitable for its purpose. In Python, json.loads performs JSON deserialization, but it does not know a particular application's requirements.[ref]
For an original example, suppose a program accepts an exact Python integer object from 0 through 10. Its validation predicate is type(x) is int and 0 <= x <= 10. After JSON decoding, inputs 0, 3 and 10 pass; -1, 11, "3", true and 3.0 fail. All are valid JSON texts. The last input becomes a floating-point object, so this particular rule rejects it even though its numerical value is integral. A different application could deliberately accept it.
The rule must therefore be explicit about its intended distinction. Converting every input to an integer before checking would change what is accepted and could lose information. Validating after such conversion answers a different question from checking the original decoded data type.
Finally, conformity to these rules is not evidence that a value is true. An invented count of 3 passes the range/type check, just as an observed count of 3 would. Validation establishes compliance with the specified predicate; establishing the underlying observation requires separate evidence.
Deserialization 2026-11-05
Deserialization reconstructs values from a representation produced according to a format such as JSON. The decoder's mapping determines the resulting runtime data types. In Python, json.loads maps a JSON object to a dictionary, an array to a list, false to False and null to None by default.[ref]
For an original example, json.loads('{"enabled":false,"items":[null,0,"0"]}') produces {'enabled': False, 'items': [None, 0, '0']}. The last two items differ: the integer zero and a string containing a digit are not interchangeable. The decoder reconstructs nested values rather than returning the displayed source text.
Syntax and application meaning require separate checks. The malformed JSON {"items":[1,2,]} raises JSONDecodeError. By contrast, {"items":"many"} parses successfully but fails a program's requirement that items be a list. That second check is data validation, beyond recognizing the format's syntax.[ref]
Nor does successful deserialization guarantee recovery of every original property. A Python tuple encoded as a JSON array normally returns as a list. A round-trip claim must specify whether it preserves values, runtime types or object identity. Character encoding and parsing contribute to the reconstruction, while the selected mapping determines which distinctions survive.
HTTP cache key 2026-11-05
An HTTP cache key is the information an HTTP cache uses to choose a stored response. The standard's minimum basis comprises the request method and target URI, while additional request information can distinguish negotiated responses or partition storage. Common caches that store only GET responses can use the URI alone for that minimum basis.[ref]
For an own example, suppose a cache holds both JSON and HTML responses for GET /report, each with Vary: Accept. Their explanatory selection inputs are (GET, /report, Accept=application/json) and (GET, /report, Accept=text/html). The target and method agree, but the nominated field distinguishes the variants. Another matching request for JSON must not receive the HTML entry merely because its target is also /report.[ref]
A request for /report?page=2 also has a different target from /report. Sharing a path prefix is not enough to identify a stored response. The example's tuples describe selection information rather than prescribe a particular serialized key or database implementation.
Field matching itself follows the specification. It can include the normalization permitted for the nominated fields; comparing every raw header string byte for byte is not the general rule. A missing field and an arbitrary different value also cannot be silently treated as equivalent.[ref]
Selection and permission to reuse are separate steps. A matching stored response must still satisfy the applicable cache controls and HTTP freshness or validation requirements. An HTTP private cache and an HTTP shared cache differ in their scope and some controls, but neither can infer complete reuse permission from a key match alone.[ref]
The key becomes especially important with HTTP content negotiation: several representations can belong to one resource without being interchangeable for every request. Identifying the selection dimensions explains both correct reuse and why one broadly shared target identifier need not yield one universal cached body.
HTTP proactive negotiation is HTTP content negotiation in which the server selects an HTTP representation using information in the client's request. Explicit preferences can describe acceptable media types, languages or content encodings; the server can also use implicit request characteristics. The specification also calls this server-driven negotiation.[ref]
Suppose /report offers both JSON and HTML. A client sends Accept: application/json, text/html;q=0.5. The omitted quality weight for JSON defaults to one, so the request expresses a stronger preference for JSON than for HTML. If the server honors this ranking and both forms are available, it returns the JSON form with Content-Type: application/json.[ref]
This can deliver the preferred representation in the first response. The client does not first need to retrieve a menu of alternatives and then make another choice. In contrast, HTTP reactive negotiation leaves selection to the client after an initial response identifies alternatives. Either approach still requires the application to decide what the available representations mean.
A server selecting on Accept can send Vary: Accept. That field identifies an additional request dimension that might affect the response, beyond the method and target identifier. A stored response chosen for one Accept value is consequently not automatically the appropriate selection for another; caching must account for the relevant variation.[ref]
The server's information is incomplete. A supported format need not be the best format for the user's intended task, and describing capabilities in every request can increase message size and disclose information about the client. The specification also permits servers to disregard negotiation preferences rather than return 406 when honoring them would leave no acceptable choice. The example's ranking policy is therefore a stated application assumption, not an unconditional protocol guarantee.[ref]
HTTP reactive negotiation 2026-11-05
HTTP reactive negotiation is HTTP content negotiation in which the client selects a representation after receiving an initial response identifying alternatives. The mechanism can be as simple as links to the available forms. The specification also calls this agent-driven negotiation.[ref]
For an invented example, a client requests /report. The response presents links to /report.html and /report.json, describing the available HTML and JSON forms. A person or client program chooses JSON and requests /report.json. The server then returns that representation. The first response can already contain useful content alongside its alternatives; reactive selection does not require it to be an otherwise empty menu.
The specification discusses alternatives in responses with status 300 or 406, but the defining feature is the client's selection after the first response. The example's suffixes are application conventions: an HTTP representation's actual media type is described by its response metadata, rather than established by a filename alone.[ref]
An extra request can add delay. In a toy model with an established connection, milliseconds per complete request/response exchange, negligible processing and transmission time, and no existing copy of the alternatives, fetching the menu and then a chosen representation takes milliseconds. A correct HTTP proactive negotiation choice in one exchange would take milliseconds under those same assumptions. These numbers illustrate the additional dependency, not a universal measured performance difference.
The tradeoff can be worthwhile when the client knows requirements that the server cannot infer, or when alternatives can be reused effectively. The server exposes the choices instead of guessing the user's preference. The standard does not prescribe a general automatic selection algorithm for the client, so providing alternatives does not itself establish that every client will make or follow a choice.[ref]
JSON 2026-11-05
JSON, short for JavaScript Object Notation, is a textual data interchange format used for serialization. Its values are objects, arrays, strings, numbers, Boolean values and null. Object member names are strings; array elements are ordered. A complete JSON text may represent a single value, including a number or string.[ref]
The format's syntax and an implementation's numerical precision are separate. For an original example, consider {"n":9007199254740993}. A JavaScript call to JSON.parse produces a Number whose decimal value is 9007199254740992; the requested integer has rounded to in the double-precision floating-point format. The same input decoded by Python's default json.loads retains the integer 9007199254740993 exactly.
Encoding the digits as {"n":"9007199254740993"} preserves them as a string in both examples, but changes the represented type. Any later numerical interpretation needs an agreed rule. RFC8259 identifies the integer interval for exact agreement with commonly used numerical implementations; it does not restrict valid JSON numerals to that interval.[ref]
For exchange between systems outside a closed ecosystem, RFC8259 requires UTF-8.[ref] Defining a textual format therefore addresses portable syntax, while faithful deserialization also requires agreement about the values an application expects.
Serialization 2026-11-05
Serialization maps structured program data into a representation that can be stored or transmitted, often a sequence of bytes. Deserialization reconstructs data according to that format. A useful format must specify which values and distinctions it preserves; writing an object's display text is not automatically a reversible encoding. JSON is one textual interchange format, with ordered arrays and objects whose member names are strings.[ref]
In Python, let value = {"coords": [2, 5], "ready": True}. Calling json.dumps(value, sort_keys=True, separators=(",", ":"), allow_nan=False) produces {"coords":[2,5],"ready":true}. Encoding this string with UTF-8 gives 29 bytes; json.loads reconstructs a value equal to value. Here serialization connects a nested runtime value, text and an explicit character encoding.[ref]
The preservation claim is deliberately specific. If coords originally contains the tuple (2, 5), the default JSON round trip produces a list instead. Equality of the chosen first example therefore proves neither preservation of every runtime type nor preservation of object identity. Format design requires deciding which such distinctions matter.
T. Bray 2026-11-05
T. Bray is credited as editor of RFC 8259, the 2017 specification of JSON as a format for serialization of structured data. The document makes both the grammar and data format interoperability requirements explicit: a shared notation is most useful when independent implementations agree on what it means.[ref]
One concrete example is duplicate object names. The invented text {"x":1,"x":2} fits the object grammar, but the specification recommends unique names because receiving implementations can handle duplicates differently. Some keep the last pair, some reject the input and some expose all pairs. A parser accepting text and two applications agreeing on its interpretation are different conditions.[ref]
The specification also requires UTF-8 for exchanged JSON outside a closed ecosystem. Character encoding, syntax and agreement on values thus contribute separately to reliable interchange.[ref]
This work illustrates a contribution through precise specification: identifying where superficially similar implementations can disagree and stating requirements that make exchange predictable. The initial-only header retains the document's editor byline.