Data Formats and Serialization (JSON-focused): Rules, Date/Number/Null Handling, and Standardizing API Responses
JSON is the default data format for most modern APIs, but “it works” is not the same as “it scales.” Inconsistent field names, ambiguous date formats, floating-point surprises, and unclear null behavior create bugs that are hard to trace—especially as multiple clients (web, mobile, partners) integrate with your API.
This post explains the core JSON rules, how to treat dates, numbers, and null values safely, and how to enforce consistent request/response schemas. At the end, you will standardize your API responses into a predictable JSON shape you can reuse across endpoints.
Table of Contents
- Key Points (Quick Rules)
- What “Serialization” Means in Practice
- JSON Rules You Must Know
- Dates and Times in JSON
- Numbers: Precision, Currency, IDs
- Null vs Missing vs Empty
- Keeping Request/Response Schemas Consistent
- Practice: Standardizing Response JSON
- Code Example: Response Wrapper + Error Format
- Reference Table: Recommended Conventions
- Step-by-Step Workflow
- Extra Considerations
- Blog Optimization Info
Key Points (Quick Rules)
- Always send JSON with
Content-Type: application/jsonand a consistent top-level response structure. - Use a single naming convention (commonly
camelCase) for fields across all requests and responses. - Represent dates as ISO 8601 strings (e.g.,
2026-01-02T09:30:00Z), not localized formats. - Be careful with JSON numbers: avoid floating-point for money; consider minor units (cents) or strings for high precision.
- Define rules for
nullvs missing fields; document them and keep them consistent. - Standardize errors: include an error code, human message, and optional field-level details.
What “Serialization” Means in Practice
Serialization is converting in-memory data structures (objects, arrays, types) into a format you can send over the network (a JSON string). Deserialization converts that JSON back into objects on the client or server.
Most bugs happen at boundaries:
- Different languages represent types differently (e.g., JavaScript has one
Number, but databases may haveDECIMAL,BIGINT). - Dates are not a native JSON type; you must choose a representation.
nullis valid JSON, but teams disagree on what it “means” unless you define it.
The goal is to choose conventions that minimize ambiguity and remain stable as your API grows.
JSON Rules You Must Know
JSON has a small set of types: object, array, string, number, boolean, and null. That simplicity is powerful, but it means some common concepts are not built-in (dates, decimals, binary data). The core rules:
- Object keys are strings and must be quoted (e.g.,
{"id": 1}). - Strings are Unicode; escape quotes and control characters properly.
- Numbers have no explicit integer/float distinction in JSON text; the consuming language decides how to parse it.
- Do not rely on key ordering inside objects; clients should treat objects as unordered maps.
A good API treats JSON as a contract, not an implementation detail. That means defining a schema and sticking to it.
Dates and Times in JSON
Because JSON has no date type, you must pick a representation. The safest and most interoperable option is an ISO 8601 string in UTC, usually with Z (Zulu time):
- Recommended:
"createdAt": "2026-01-02T09:30:00Z" - Avoid:
"01/02/2026 18:30"(ambiguous across locales)
If you need a date without time (e.g., a birthday), use YYYY-MM-DD:
"birthDate": "1995-10-31"
If your system needs time zones (for scheduling, local business hours), store timestamps in UTC and send a separate time zone field when relevant:
"startsAt": "2026-01-02T09:30:00Z""timeZone": "Asia/Seoul"
Numbers: Precision, Currency, IDs
JSON numbers look simple, but they can become tricky in real systems. Many clients (especially JavaScript) parse numbers into IEEE 754 floating-point, which can introduce precision errors:
- Example issue:
0.1 + 0.2may not equal exactly0.3in floating-point systems.
Currency
For money, avoid floats. Two common safe approaches:
- Minor units (recommended for many APIs): store as integers (cents).
"amount": 1299,"currency": "USD"means $12.99 - String decimal: preserve precision as a string.
"amount": "12.99","currency": "USD"
Large IDs
Very large integers (e.g., database IDs) can exceed safe integer ranges in some clients. To avoid client-side rounding:
- Use string IDs:
"id": "9223372036854775807" - Or use prefixed IDs:
"id": "ord_12345"
Rules of Thumb
- Use JSON numbers for counts, sizes, and values that fit safely in common clients.
- Use strings for high-precision decimals (rates) or extremely large integers (IDs) if clients might lose precision.
Null vs Missing vs Empty
Many schema inconsistencies come from unclear handling of null. Define what each state means:
- Missing field: “not provided” or “not applicable in this response.”
null: “explicitly unknown” or “intentionally cleared.”- Empty string (
""): “known to be blank.” - Empty array (
[]): “known to have zero items.”
A practical beginner-friendly policy:
- Use missing fields for optional data not included in the response shape.
- Use
nullonly when you need to explicitly say “no value,” or when the client can sendnullto clear a value (document this). - Prefer empty arrays over
nullarrays for list fields (e.g.,"items": []instead of"items": null).
Keeping Request/Response Schemas Consistent
Consistency is what makes an API easy for beginners. Here are the most valuable rules to enforce:
1) Keep Field Names Consistent
- Pick
camelCase(common in JSON) orsnake_case, then stick with it everywhere. - Do not mix
created_atin one endpoint andcreatedAtin another.
2) Keep Types Stable
A field should not change type across endpoints or versions. If totalAmount is an integer minor unit in one place, it should not become a string in another without a versioned migration plan.
3) Use Reusable Models
If you return an Order object from multiple endpoints, keep it structurally consistent. If some endpoints need less data, either:
- Use partial objects but keep the same meaning for included fields, or
- Return a “summary” model intentionally (e.g.,
OrderSummary) and document it.
4) Be Predictable About Lists and Pagination
List endpoints should consistently return:
- A list field (e.g.,
items) that is always an array - A
metasection for pagination information
Practice: Standardizing Response JSON
The fastest way to make your API predictable is to standardize the top-level response shape. A beginner-friendly and widely-used pattern is an “envelope” with success, data, error, and meta.
Standard Envelope (Recommended)
success: booleandata: the payload (object, array, or null)error: null or an object (code/message/details)meta: optional metadata (pagination, requestId, timing)
Now apply this to three common scenarios:
- Detail response: one entity (e.g., an order).
- List response: multiple entities with pagination.
- Error response: validation error with field-level details.
Design Targets (Your Exercise)
- Pick a consistent date format (ISO 8601 UTC) and apply it across all entities.
- Pick a money format (minor units integer or decimal string) and apply it everywhere.
- Decide rules for
null(when allowed, when avoided) and document them in the schema. - Ensure every endpoint returns the same envelope shape, even on errors.
Code Example: Response Wrapper + Error Format
The following JSON examples demonstrate standardized success and error responses. You can copy these shapes into your API documentation or OpenAPI/JSON Schema definitions.
{
"success": true,
"data": {
"orderId": "ord_12345",
"status": "paid",
"totalAmount": 1299,
"currency": "USD",
"createdAt": "2026-01-02T09:30:00Z"
},
"error": null,
"meta": {
"requestId": "req_8f1c2a",
"serverTime": "2026-01-02T09:30:01Z"
}
}
/* List response with pagination */
{
"success": true,
"data": {
"items": [
{
"orderId": "ord_12345",
"status": "paid",
"totalAmount": 1299,
"currency": "USD",
"createdAt": "2026-01-02T09:30:00Z"
}
]
},
"error": null,
"meta": {
"page": 1,
"size": 20,
"totalItems": 1,
"totalPages": 1,
"sort": "-createdAt"
}
}
/* Validation error response */
{
"success": false,
"data": null,
"error": {
"code": "VALIDATION_ERROR",
"message": "One or more fields are invalid.",
"details": [
{ "field": "email", "reason": "Invalid email format." },
{ "field": "birthDate", "reason": "Expected YYYY-MM-DD." }
]
},
"meta": {
"requestId": "req_91b7de"
}
}
Notice how the envelope does not change shape between success and failure. Clients can always check success, then read data or error. This drastically reduces “special-case parsing” on the frontend.
Reference Table: Recommended Conventions
| Area | Recommendation | Why It Helps | Example |
|---|---|---|---|
| Field naming | Use one style consistently (e.g., camelCase) |
Reduces mapping and confusion across endpoints | createdAt, totalAmount |
| Dates | ISO 8601 UTC strings | Avoids locale ambiguity and time zone bugs | 2026-01-02T09:30:00Z |
| Money | Integer minor units or decimal string | Avoids floating-point precision errors | 1299 + USD |
| Null handling | Define meaning; prefer empty arrays for lists | Prevents client-side special cases | "items": [] |
| Response shape | Use a stable envelope (success, data, error, meta) |
Simplifies clients and improves observability | requestId, pagination in meta |
| Errors | Standardize code, message, optional details |
Enables reliable UI handling and debugging | VALIDATION_ERROR |
Step-by-Step Workflow
- Write down your core entities and their fields (e.g., User, Order, Shipment).
- Choose conventions: naming style, date format, money format, null policy.
- Define a standard response envelope and error structure.
- Create reusable helpers on the server (e.g.,
ok(data, meta),fail(code, message, details)). - Document request/response schemas (JSON Schema or OpenAPI) and keep them version-controlled.
- Add contract tests that validate example responses match the schema.
- Roll out endpoint by endpoint, keeping backward compatibility or versioning when needed.
Extra Considerations
- Boolean flags: keep them boolean (
true/false), not"Y"/"N". If your database usesY/N, convert at the API layer. - Enums: document allowed string values (e.g.,
statuscan bepending,paid,canceled). - Backward compatibility: adding fields is usually safe; renaming/removing fields should be versioned or handled with a migration plan.
- Consistency across services: if you have multiple microservices, define shared conventions (date, money, error codes) to avoid integration friction.
- Debugging: including
requestIdinmetahelps connect client errors to server logs quickly.
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

0 댓글