Skip to main content
Course/Module 8/Topic 3 of 5Intermediate

JavaScript JSON & Data Serialization

Master JSON parsing, stringification, and data serialization techniques for working with APIs and data storage

40 minBy Priygop TeamLast updated: Feb 2026

JSON Fundamentals

JSON (JavaScript Object Notation) is a lightweight data interchange format that's easy for humans to read and write, and easy for machines to parse and generate. It's the standard format for API communication and data storage.

JSON Operations

Example
// JSON.stringify - Convert JavaScript to JSON
const user = {
    name: 'John Doe',
    age: 30,
    email: 'john@example.com',
    isActive: true,
    hobbies: ['reading', 'coding', 'gaming'],
    address: {
        street: '123 Main St',
        city: 'New York',
        zipCode: '10001'
    },
    birthDate: new Date('1993-05-15'),
    undefinedValue: undefined,
    functionValue: function() { return 'hello'; }
};

// Basic stringification
const jsonString = JSON.stringify(user);
console.log(jsonString);

// Stringify with indentation
const prettyJson = JSON.stringify(user, null, 2);
console.log(prettyJson);

// Stringify with replacer function
const replacer = (key, value) => {
    if (key === 'email') {
        return value.replace(/./g, '*'); // Mask email
    }
    if (typeof value === 'function') {
        return undefined; // Remove functions
    }
    if (value instanceof Date) {
        return value.toISOString(); // Convert dates
    }
    return value;
};

const maskedJson = JSON.stringify(user, replacer, 2);
console.log(maskedJson);

// Stringify with replacer array
const selectedFields = JSON.stringify(user, ['name', 'age', 'hobbies'], 2);
console.log(selectedFields);

// JSON.parse - Convert JSON to JavaScript
const parsedUser = JSON.parse(jsonString);
console.log(parsedUser.name); // 'John Doe'

// Parse with reviver function
const reviver = (key, value) => {
    if (key === 'birthDate') {
        return new Date(value);
    }
    if (key === 'email' && typeof value === 'string') {
        return value.toLowerCase();
    }
    return value;
};

const revivedUser = JSON.parse(jsonString, reviver);
console.log(revivedUser.birthDate instanceof Date); // true

// Error handling
function safeParse(jsonString) {
    try {
        return JSON.parse(jsonString);
    } catch (error) {
        console.error('JSON parse error:', error.message);
        return null;
    }
}

function safeStringify(obj) {
    try {
        return JSON.stringify(obj);
    } catch (error) {
        console.error('JSON stringify error:', error.message);
        return null;
    }
}

// Deep cloning with JSON
function deepClone(obj) {
    return JSON.parse(JSON.stringify(obj));
}

// Data validation
function validateJSON(data, schema) {
    const requiredFields = schema.required || [];
    const fieldTypes = schema.types || {};
    
    for (const field of requiredFields) {
        if (!(field in data)) {
            throw new Error(`Missing required field: ${field}`);
        }
    }
    
    for (const [field, expectedType] of Object.entries(fieldTypes)) {
        if (field in data) {
            const actualType = typeof data[field];
            if (actualType !== expectedType) {
                throw new Error(`Field ${field} should be ${expectedType}, got ${actualType}`);
            }
        }
    }
    
    return true;
}

// Schema definition
const userSchema = {
    required: ['name', 'email'],
    types: {
        name: 'string',
        age: 'number',
        email: 'string',
        isActive: 'boolean'
    }
};

// Test validation
try {
    validateJSON(user, userSchema);
    console.log('User data is valid');
} catch (error) {
    console.error('Validation error:', error.message);
}

// JSON utilities
class JSONUtils {
    static parseFile(fileContent) {
        return safeParse(fileContent);
    }
    
    static stringifyFile(data, pretty = true) {
        return pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
    }
    
    static merge(...objects) {
        return objects.reduce((result, obj) => ({ ...result, ...obj }), {});
    }
    
    static flatten(obj, prefix = '') {
        const flattened = {};
        
        for (const [key, value] of Object.entries(obj)) {
            const newKey = prefix ? `${prefix}.${key}` : key;
            
            if (value && typeof value === 'object' && !Array.isArray(value)) {
                Object.assign(flattened, this.flatten(value, newKey));
            } else {
                flattened[newKey] = value;
            }
        }
        
        return flattened;
    }
    
    static unflatten(obj) {
        const unflattened = {};
        
        for (const [key, value] of Object.entries(obj)) {
            const keys = key.split('.');
            let current = unflattened;
            
            for (let i = 0; i < keys.length - 1; i++) {
                const k = keys[i];
                current[k] = current[k] || {};
                current = current[k];
            }
            
            current[keys[keys.length - 1]] = value;
        }
        
        return unflattened;
    }
    
    static diff(obj1, obj2) {
        const allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
        const diff = {};
        
        for (const key of allKeys) {
            if (JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) {
                diff[key] = {
                    old: obj1[key],
                    new: obj2[key]
                };
            }
        }
        
        return diff;
    }
    
    static patch(obj, patch) {
        const result = { ...obj };
        
        for (const [key, value] of Object.entries(patch)) {
            if (value === null) {
                delete result[key];
            } else {
                result[key] = value;
            }
        }
        
        return result;
    }
}

// Test JSON utilities
const obj1 = { a: 1, b: { c: 2, d: 3 } };
const obj2 = { a: 1, b: { c: 2, d: 4 }, e: 5 };

console.log('Flattened:', JSONUtils.flatten(obj1));
console.log('Diff:', JSONUtils.diff(obj1, obj2));
console.log('Patched:', JSONUtils.patch(obj1, { b: { c: 2, d: 4 }, e: 5 }));

Practice Exercise: JSON

Example
// Exercise: Build a JSON Data Manager
class JSONDataManager {
    constructor() {
        this.data = new Map();
        this.schemas = new Map();
    }
    
    setSchema(name, schema) {
        this.schemas.set(name, schema);
    }
    
    validate(data, schemaName) {
        const schema = this.schemas.get(schemaName);
        if (!schema) {
            throw new Error(`Schema '${schemaName}' not found`);
        }
        
        return validateJSON(data, schema);
    }
    
    set(key, value, schemaName = null) {
        if (schemaName) {
            this.validate(value, schemaName);
        }
        
        this.data.set(key, JSON.parse(JSON.stringify(value)));
        return this;
    }
    
    get(key) {
        const value = this.data.get(key);
        return value ? JSON.parse(JSON.stringify(value)) : null;
    }
    
    delete(key) {
        return this.data.delete(key);
    }
    
    has(key) {
        return this.data.has(key);
    }
    
    keys() {
        return Array.from(this.data.keys());
    }
    
    values() {
        return Array.from(this.data.values());
    }
    
    size() {
        return this.data.size;
    }
    
    clear() {
        this.data.clear();
    }
    
    export() {
        const exportData = {};
        for (const [key, value] of this.data) {
            exportData[key] = value;
        }
        return JSON.stringify(exportData, null, 2);
    }
    
    import(jsonString) {
        const data = JSON.parse(jsonString);
        for (const [key, value] of Object.entries(data)) {
            this.data.set(key, value);
        }
    }
    
    query(filter) {
        const results = [];
        
        for (const [key, value] of this.data) {
            if (this.matchesFilter(value, filter)) {
                results.push({ key, value });
            }
        }
        
        return results;
    }
    
    matchesFilter(value, filter) {
        for (const [key, expectedValue] of Object.entries(filter)) {
            if (value[key] !== expectedValue) {
                return false;
            }
        }
        return true;
    }
}

// Exercise: Build a JSON API Client
class JSONApiClient {
    constructor(baseUrl) {
        this.baseUrl = baseUrl;
        this.headers = {
            'Content-Type': 'application/json'
        };
    }
    
    setHeader(key, value) {
        this.headers[key] = value;
        return this;
    }
    
    async request(endpoint, options = {}) {
        const url = `${this.baseUrl}${endpoint}`;
        const config = {
            headers: { ...this.headers, ...options.headers },
            ...options
        };
        
        if (options.body) {
            config.body = JSON.stringify(options.body);
        }
        
        const response = await fetch(url, config);
        
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        
        return await response.json();
    }
    
    async get(endpoint) {
        return this.request(endpoint, { method: 'GET' });
    }
    
    async post(endpoint, data) {
        return this.request(endpoint, {
            method: 'POST',
            body: data
        });
    }
    
    async put(endpoint, data) {
        return this.request(endpoint, {
            method: 'PUT',
            body: data
        });
    }
    
    async delete(endpoint) {
        return this.request(endpoint, { method: 'DELETE' });
    }
    
    async patch(endpoint, data) {
        return this.request(endpoint, {
            method: 'PATCH',
            body: data
        });
    }
}

// Test the exercises
const dataManager = new JSONDataManager();

// Set up schemas
dataManager.setSchema('user', {
    required: ['name', 'email'],
    types: { name: 'string', email: 'string', age: 'number' }
});

dataManager.setSchema('product', {
    required: ['name', 'price'],
    types: { name: 'string', price: 'number', category: 'string' }
});

// Add data
dataManager.set('user:1', {
    name: 'John Doe',
    email: 'john@example.com',
    age: 30
}, 'user');

dataManager.set('product:1', {
    name: 'Laptop',
    price: 999.99,
    category: 'Electronics'
}, 'product');

// Query data
const users = dataManager.query({ age: 30 });
console.log('Users aged 30:', users);

// Export/Import
const exported = dataManager.export();
console.log('Exported data:', exported);

const newManager = new JSONDataManager();
newManager.import(exported);
console.log('Imported data size:', newManager.size());

// Test API client
const api = new JSONApiClient('https://api.example.com')
    .setHeader('Authorization', 'Bearer token123');

// Simulate API calls (these would fail without a real server)
// api.get('/users')
//     .then(users => console.log('Users:', users))
//     .catch(error => console.error('API error:', error));
Chat on WhatsApp
Priygop - Leading Professional Development Platform | Expert Courses & Interview Prep