JSON carries structured values between browser and server, but decoding valid JSON is only the first step. The client must check status and content type; the server must validate the decoded shape, types, permissions, and business rules before trusting any field.
JSON (JavaScript Object Notation) is a lightweight, text-based data format that is easy for humans to read and write, and easy for machines to parse and generate. It is the de facto standard for data exchange in modern AJAX applications.
JSON supports six data types: string, number, boolean, null, object, and array.
// JavaScript object -> JSON string (for sending to server)
const user = {
name: 'Alice',
age: 30,
active: true,
roles: ['admin', 'editor'],
address: { city: 'New York', zip: '10001' }
};
const jsonString = JSON.stringify(user);
console.log(jsonString);
// '{"name":"Alice","age":30,"active":true,"roles":["admin","editor"],"address":{"city":"New York","zip":"10001"}}'
// Pretty-print with indentation (useful for debugging)
console.log(JSON.stringify(user, null, 2));
// JSON string -> JavaScript object (after receiving from server)
const received = '{"id":1,"title":"Hello","published":true}';
const post = JSON.parse(received);
console.log(post.title); // "Hello"
console.log(typeof post); // "object"
// JSON.parse with error handling
try {
const bad = JSON.parse('{ invalid json }');
} catch (e) {
console.error('Parse error:', e.message);
}
// Sending JSON to the server
const payload = {
username: 'alice',
email: 'alice@example.com',
preferences: { theme: 'dark', notifications: true }
};
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // REQUIRED when sending JSON
'Accept': 'application/json' // Tell server we expect JSON back
},
body: JSON.stringify(payload) // Convert object to JSON string
})
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json(); // Parse JSON response
})
.then(data => {
console.log('Server response:', data);
// data is already a JS object - no JSON.parse() needed
console.log('New user ID:', data.id);
})
.catch(err => console.error('Error:', err));
| Feature | JSON | XML |
|---|---|---|
| Verbosity | Compact | Verbose (opening/closing tags) |
| Readability | Easy to read | Harder to read |
| Parsing | Native JS (JSON.parse) | Requires DOMParser |
| Data types | Supports arrays, booleans, null | Everything is a string |
| Comments | Not supported | Supported |
| Schema validation | JSON Schema | XSD, DTD |
| Usage today | Dominant in REST APIs | Legacy systems, SOAP |
// ---- Pitfall 1: undefined values are dropped ----
const obj = { name: 'Alice', score: undefined, active: true };
console.log(JSON.stringify(obj));
// '{"name":"Alice","active":true}' - score is gone!
// ---- Pitfall 2: Circular references throw an error ----
const a = {};
const b = { ref: a };
a.ref = b; // circular!
try {
JSON.stringify(a); // throws TypeError
} catch (e) {
console.error('Circular reference:', e.message);
}
// ---- Pitfall 3: Dates become strings ----
const event = { name: 'Launch', date: new Date() };
const str = JSON.stringify(event);
const parsed = JSON.parse(str);
console.log(typeof parsed.date); // "string" - not a Date object!
// Fix: convert back manually
const realDate = new Date(parsed.date);
// ---- Pitfall 4: JSON keys must be double-quoted strings ----
// Valid JSON: { "name": "Alice" }
// Invalid JSON: { name: 'Alice' } <- single quotes and unquoted keys
Send application/json when the request body is JSON and use JSON.stringify once. Dates become strings by convention, undefined object properties are omitted, and large integer identifiers can lose precision in JavaScript; design the API representation deliberately.
On response, handle an empty body or non-JSON error without masking the original status with a parsing exception. Never insert response strings through innerHTML unless they have been sanitized for that exact HTML context. Prefer textContent or structured DOM creation.
JSON.parse proves only that the text follows JSON grammar. It does not prove that an object has the required keys, that an id is positive, or that a role is permitted. Validate the decoded structure at the client boundary for predictable UI behavior and again on the server for security.
Use a documented schema for shared APIs when the contract is large or generated clients depend on it. Reject unknown or missing fields according to a deliberate compatibility policy instead of silently guessing.
function isUser(value) {\n return typeof value === "object" && value !== null\n && Number.isInteger(value.id)\n && typeof value.name === "string";\n}\n\nconst response = await fetch("/api/user/7");\nif (!response.ok) throw new Error("HTTP " + response.status);\nconst value = await response.json();\nif (!isUser(value)) throw new Error("Unexpected user response");
The check narrows unknown transport data before application code trusts its fields.
| JavaScript Value | JSON Result | Contract Choice |
|---|---|---|
| Date | ISO-style string by convention | Parse only fields documented as dates. |
| BigInt | JSON.stringify throws | Encode as a decimal string when exactness matters. |
| undefined property | Omitted | Use null when absence must be explicit. |
| NaN or Infinity | null | Reject or encode a named state. |
| Large integer | May lose JS precision | Send identifiers as strings. |
Try this next
0 of 2 completed
Explore 500+ free tutorials across 20+ languages and frameworks.