JSON, Content Types, and API Serialization Explained
Learn how JSON representations, media types, and serialization rules shape API compatibility, validation, and reliable client-server data exchange.
JSON is easy to exchange across services, but dates, money, large identifiers, and missing fields need explicit rules. The guide explains how Content-Type and Accept describe each message, where parsing and validation belong, and how to evolve a representation without breaking deployed clients. It also covers body limits, failure cases, and what to record when serialization goes wrong.
JSON, Content Types, and API Serialization Explained
Introduction
JSON is an easy format for clients and servers to exchange, but its simplicity leaves important details to the API contract. Dates, decimal amounts, large identifiers, omitted fields, and null values can mean different things across languages unless their representation is explicit.
This guide explains how media types describe request and response formats, how to parse and validate JSON at the service boundary, and how to evolve serialization safely. It also covers operational limits, security, and common compatibility failures.
A media type describes the representation
Content-Type tells the receiver how to interpret a message body, such as application/json for JSON. Accept tells the server which response formats the client can handle. These headers are part of the contract: reject unsupported request formats clearly, and return a representation the client requested when possible.
Serialization is a contract
JSON has objects, arrays, strings, numbers, booleans, and null; it has no native date, decimal, or binary type. Dates are commonly serialized as ISO 8601 strings with a timezone, such as 2026-09-30T08:15:00Z. Money should avoid binary floating-point ambiguity; many APIs send an integer number of minor units plus a currency, or a decimal string with documented precision. Large identifiers should often be strings because JavaScript cannot exactly represent every 64-bit integer.
Be explicit about field rules. For a patch request, omitted may mean “leave unchanged” while null may mean “clear this value.” For a response, omitting a field can mean it is unavailable or not selected. Document those differences. Keep enum values stable, define whether unknown fields are ignored or rejected, and avoid changing a field’s type in place.
Example request and response
POST /api/invoices HTTP/1.1
Content-Type: application/json
Accept: application/json
{"customerId":"cus_812","currency":"USD","amountMinor":2599}
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
{"id":"inv_51","amountMinor":2599,"currency":"USD","createdAt":"2026-09-30T08:15:00Z"}
The wire format uses strings for identifiers and a UTC timestamp. The field amountMinor makes units explicit; clients do not have to infer whether 25.99 means dollars, cents, or a floating-point approximation.
Parse and validate at the boundary
flowchart LR
A[HTTP bytes] --> B[Check media type and size]
B --> C[Parse JSON]
C --> D[Validate schema and business rules]
D --> E[Convert to domain types]
E --> F[Run application operation]
F --> G[Serialize response]
Keep parsing separate from domain logic. A parser can reject malformed JSON; schema validation can reject missing fields or the wrong type; business validation can reject an unsupported currency. Return actionable field errors without echoing secrets or raw attacker-controlled content.
When to use and when not to use
JSON is a strong default for web APIs because browsers, command-line tools, and most languages support it. Use it for ordinary request-response data where readability and broad interoperability matter. Consider binary encodings when payload size or CPU cost is measured and material, or use a streaming format when consumers process an unbounded sequence. Do not switch formats based on benchmark claims alone: network compression, object shape, parser behavior, and client languages can change the result.
Trade-Off Table
| Representation | Strength | Cost |
|---|---|---|
| JSON | Readable and widely supported | Verbose; dates and decimals need conventions |
| Protobuf | Compact schema-based messages | Requires generated code and schema workflow |
| Form data | Fits browser uploads and files | Awkward for nested structured objects |
| Plain text | Simple for a single value or export | Weak typing and limited structure |
Implementation snippet
Validate media type, parsing, and schema separately. This framework-neutral TypeScript example shows the boundary shape:
async function readCreateInvoice(request: Request) {
if (!request.headers.get("content-type")?.includes("application/json")) {
throw new HttpError(415, "unsupported_media_type");
}
const raw: unknown = await request.json();
return CreateInvoiceSchema.parse(raw);
}
The schema should bound string lengths and numeric ranges, reject unexpected precision where relevant, and produce a typed application input. Do not let a permissive JSON parser decide business rules.
Production failure scenarios and mitigations
A client parses a 64-bit numeric ID as a rounded JavaScript number and requests the wrong record. Serialize large IDs as strings. A timestamp without an offset is interpreted in local time, shifting a billing cutoff; require an explicit timezone and test daylight-saving boundaries. A deployment changes amount from number to string and old clients crash; add a new field or version the contract, then deprecate gradually. Oversized bodies exhaust memory; enforce request size limits before parsing.
Observability checklist
- Count malformed JSON, schema failures, unsupported media types, and business validation failures separately.
- Record payload size buckets and serialization latency, never full private request bodies by default.
- Track unknown-field rates during migrations to find older or newer clients.
- Attach a request ID to errors so support can trace the contract failure without retaining sensitive data.
Security and Compliance Notes
Treat JSON input as untrusted. Enforce body size and nesting limits, validate every field, and avoid unsafe object merging that could allow prototype pollution in some runtimes. Do not log access tokens, passwords, payment data, or personal records. Return only fields the caller is allowed to see, and make sure error responses do not echo secrets or unrestricted input. For regulated data, define retention and access controls for serialized payloads, logs, and exports; the applicable obligations depend on the data and jurisdiction.
Common Pitfalls / Anti-Patterns
Using floating-point arithmetic for money can silently change a value during serialization. Treating null and a missing field as equivalent breaks partial-update contracts. Returning an HTML error page from a JSON API leaves clients with a parsing failure instead of a useful API error, while accepting arbitrary content types can send bytes through the wrong parser. Avoid changing a field’s type in place or assuming that a valid JSON document is also a valid business request.
Quick Recap Checklist
- Set Content-Type to describe the body and use Accept to state response formats the client can read.
- Keep field names, number handling, date formats, and null semantics stable and documented.
- Validate parsed input at the API boundary before business logic uses it.
- Treat serialization changes as compatibility changes for deployed clients.
Interview Questions
Content-Type describes the representation in the current message body. Accept tells the server which response representation the client can consume.null clears it, but the API must validate and document that choice consistently.Accept that the server cannot provide.
Further Reading
- Requests, Responses, and Error Shapes — practical conventions for API message bodies and errors.
- API Contracts and Consumer Expectations — how representation rules fit into a shared contract.
- Methods, Status Codes, and Headers — how HTTP headers and status codes shape exchanges.
- RFC 8259: The JSON Data Interchange Format — JSON syntax and interoperability requirements.
- JSON Schema: Getting Started — describing and validating JSON structures.
Conclusion
JSON makes APIs approachable, but predictable serialization takes deliberate choices. Specify edge cases in the contract, validate at the boundary, and keep changes compatible for deployed clients.
Category
Related Posts
API Request, Response, and Error Shapes Clients Can Trust
Design consistent API request and response envelopes, validation errors, and problem details so client developers can handle success and failure reliably.
API Resource Names, Relationships, and Collections
Model API URLs around stable resources and relationships, with clear collection behavior that clients can navigate without learning server internals.
HTTP Methods, Status Codes, and Headers in API Design
Choose HTTP methods that match the operation, return status codes clients can act on, and use headers for metadata, caching, and safe retries.