Stage 3. JSON in API
In API work, JSON should be treated as a public contract between client and server. This contract is consumed not only by backend developers, but also by frontend apps, mobile clients, automated tests, partner integrations, and analytics pipelines. If the contract is vague, even a small change can break another system. That is why JSON must be designed as a stable interface with clear fields, predictable types, and explicit error rules.
1. What JSON Is in Simple Terms
JSON is a text data format based on objects {}, arrays [], and key: value pairs. Its main API advantage is interoperability: the same payload can be parsed by Java, JavaScript, Python, Go, and many other runtimes. A client does not need to know backend internals; it only needs a reliable JSON contract.
For beginners, it is important to separate format from meaning. Format answers: “Is this valid JSON text?” Meaning answers: “Does this data satisfy API business rules?” For example, "twenty" in age can be valid JSON syntax and still be invalid for an API that expects a numeric value.
2. Minimal Syntax Rules That Break Requests Most Often
- Keys must use double quotes:
"email", notemail. - String values must use double quotes:
"Anna", not'Anna'. - Commas separate items but never appear after the final field.
- Field types must match the contract: number, string, boolean, array, object.
nullis an explicit “empty” value, not the same as “missing field.”
3. Core JSON Types and How They Are Used in APIs
{
"id": 42,
"name": "Anna",
"isActive": true,
"tags": ["backend", "java"],
"profile": {
"city": "Kyiv"
},
"middleName": null
}
| Type | Example | Practical meaning |
|---|---|---|
string | "[email protected]" | Text values such as email or name |
number | 27 | Numeric values such as age or quantity |
boolean | true | Flag values for enabled/disabled states |
array | ["a", "b"] | Ordered list of values |
object | {"city":"Kyiv"} | Group of related fields |
null | null | Explicitly empty value |
4. How JSON Flows Through a Server
For debugging and learning, it helps to remember a simple pipeline:
flowchart LR
A[HTTP Request with JSON] --> B[Parse JSON]
B --> C[Validate Fields and Types]
C --> D[Run Business Rules]
D --> E[JSON Response or Error]
If parsing fails, the client should receive a format error. If parsing passes but validation fails, the client should receive field-level validation errors. Only valid data reaches business logic. This separation keeps API behavior predictable and easier to automate.
5. Separate Internal Models from External DTO Contracts
Internal models evolve often: storage details change, technical fields appear, and domain internals are refactored. Public API contracts should evolve more carefully. If you return internal entities directly, any internal refactor can become a client-facing breaking change. DTOs give control by explicitly defining what external consumers can rely on.
6. Keep Error Format Consistent
{
"error": "validation_failed",
"fields": {
"email": "must be valid"
},
"traceId": "d1f1c9a2"
}
A unified error schema is required across endpoints. Then frontend and mobile clients can implement one reusable error handler: display message, highlight invalid fields, and log traceId for support. This reduces duplicated code and makes failures easier to diagnose.
7. Date and Time: the Most Common Integration Pitfall
A frequent hidden API defect is inconsistent time representation. One endpoint returns UTC, another returns local time without timezone, and a third returns custom text format. As a result, regional reports drift and “last 24 hours” filters behave differently. A practical beginner rule is to standardize one time format for all endpoints, usually ISO 8601 in UTC.
8. Safe Contract Evolution Rules
- Add new fields as optional by default.
- Do not change existing field types without migration.
- Do not remove required fields immediately; provide a transition window.
- Version the API when compatibility risk is high.
9. Beginner Checklist Before Releasing an Endpoint
- Are field names readable without backend source code?
- Are required vs optional fields explicitly documented?
- Is error format consistent across all related endpoints?
- Is date/time format uniform everywhere?
- Are there tests for failure paths, not only success paths?
10. How the Same JSON Is Read in Java and Python
Take a simple API response:
{
"userId": 42,
"email": "[email protected]",
"active": true
}
In Java, teams often use Jackson to map JSON into a DTO object. This is convenient for strong typing and validation-oriented code flows.
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonReadExample {
static class UserDto {
public int userId;
public String email;
public boolean active;
}
public static void main(String[] args) throws Exception {
String json = "{\"userId\":42,\"email\":\"[email protected]\",\"active\":true}";
ObjectMapper mapper = new ObjectMapper();
UserDto user = mapper.readValue(json, UserDto.class);
System.out.println(user.userId); // 42
System.out.println(user.email); // [email protected]
System.out.println(user.active); // true
}
}
In Python, the same payload is typically parsed with the standard json module. The result is a dictionary (dict) accessed by keys.
import json
raw = '{"userId": 42, "email": "[email protected]", "active": true}'
data = json.loads(raw)
print(data["userId"]) # 42
print(data["email"]) # [email protected]
print(data["active"]) # True
The core beginner takeaway is this: the JSON contract stays the same across languages; only parsing tools differ. That is why stable field structure matters more than client technology choice.
Practical scenario
A team added createdAt as local time without timezone. The UI looked correct in one environment, but cross-region reports became inconsistent. Investigation showed that downstream services interpreted the same value differently: some as UTC, some as local time. The failure was not in business logic but in an under-specified JSON contract. A single explicit time standard defined in advance would have prevented the incident.