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.

published: reading time: 8 min read author: GeekWorkBench
Quick Summary

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

1. Why might an API serialize a large integer identifier as a string?
Some clients, notably JavaScript clients using the standard number type, cannot represent all 64-bit integers exactly. A string preserves every digit across languages.
2. What is the difference between Content-Type and Accept?
Content-Type describes the representation in the current message body. Accept tells the server which response representation the client can consume.
3. How should a partial update distinguish null from an omitted field?
Define the semantics in the contract. A common rule is that omission leaves the value unchanged and explicit null clears it, but the API must validate and document that choice consistently.
4. When should an API return 415 Unsupported Media Type versus 406 Not Acceptable?
Use 415 when the request body uses a media type the endpoint does not accept. Use 406 when the client requests a response representation through Accept that the server cannot provide.
5. Why do APIs often represent money as minor units or a decimal string?
Binary floating-point cannot represent every decimal amount exactly. Integer minor units or a documented decimal string preserve the intended value and precision across clients.
6. What should an API require when serializing timestamps?
Use a documented format such as ISO 8601 and include a timezone or UTC offset. An unqualified local timestamp can be interpreted differently by clients in different regions.
7. How do parsing, schema validation, and business validation differ?
Parsing checks that the bytes form valid JSON. Schema validation checks structure and field types. Business validation checks whether those values are allowed for the operation, such as whether a currency is supported.
8. How should an API handle unknown JSON fields?
Choose and document whether the API ignores or rejects unknown fields. The policy should be consistent across endpoints so clients can evolve without unexpected data loss or silent mistakes.
9. Why enforce request-body size and nesting limits before processing JSON?
Large or deeply nested bodies can consume excessive memory and CPU during parsing. Rejecting them at the boundary limits resource use before application logic runs.
10. Why can changing a JSON field's type break existing API clients?
Clients often bind fields to concrete types when parsing responses. A change from number to string, for example, can cause parsing errors or incorrect behavior, so introduce a compatible field or versioned contract instead.

Further Reading

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-design #http #error-handling

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.

#api-design #rest #resource-modeling

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.

#api-design #http #rest