Tutorials Logic, IN info@tutorialslogic.com

JSON with AJAX: Encoding, Validation, and API Boundaries

JSON Boundary

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 Value Model

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.

JSON.stringify() and JSON.parse()

JSON.stringify() and JSON.parse()
// 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 and Receiving JSON in AJAX

Sending JSON with Fetch and Receiving JSON

Sending JSON with Fetch and Receiving JSON
// 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));

JSON vs XML Comparison

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

Common JSON Pitfalls

Common JSON Pitfalls
// ---- 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

Encoding Contract

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.

Shape Validation

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.

Validate a User Response

Validate a User Response
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.

Representation Limits

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.
Before you move on

JSON Boundary Review

5 checks
  • The request and response advertise the intended media type.
  • Decoded values are treated as unknown until validated.
  • Dates, exact identifiers, and missing values have documented representations.
  • Malformed and non-JSON error bodies preserve the original HTTP context.
  • Rendered strings use a safe output context.

JSON Contract Failures

  • Parsed means trusted

    Validate shape, types, permissions, and business rules.
  • Error body always parsed as JSON

    Check status and Content-Type before selecting a decoder.
  • Large identifier becomes a number

    Represent exact identifiers as strings across the API.
  • Response text inserted as HTML

    Use textContent or context-aware sanitization.

Try this next

Test a JSON Contract

0 of 2 completed

  1. Validate a product response and make a missing price fail at the request boundary. Test null, array, and wrong-type cases.
  2. Round-trip an identifier larger than Number.MAX_SAFE_INTEGER without precision loss. Use a decimal string.
Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.