An Introduction to JSON: How Web Apps Exchange Data

Building a web application today is like assembling an international team- the user interface, backend server, database, and third-party services often speak completely different native languages.

Similarly, your frontend might be a single-page app built with React running inside a browser’s JavaScript engine. Your backend API might be powered by Python and Flask or Django, while a microservice next door runs on Go or Java, connected to a PostgreSQL database.

Despite operating on fundamentally distinct programming paradigms, these isolated environments must constantly share information, whether it’s authenticating a login attempt, displaying a user profile, or updating a shopping cart in real time.

To understand why we need a format like JSON, we first have to understand how programming languages handle data in memory:

Language-Speceific Incompatibility

In-memory data structures are exclusive to their host language.

  • JavaScript stores structured data as Objects and Maps.
  • Python stores structured data as Dictionaries (dict).
  • Java uses HashMaps or class instances.
  • C++ uses structs or standard library containers.

A Python backend cannot directly stream its in-memory dictionary data to a JavaScript browser. JavaScript has no native understanding of Python’s memory layout or binary representations.

So, how would they interact?

Computer networks (routers, switches, and standard HTTP servers) do not understand complex code structures or objects. Networks transmit raw bytes and text. For data to travel over the wire, it must be flattened down into a continuous text stream, a process known as serialization. Without a universal standard, every developer pairing (e.g., Python-to-JavaScript, Java-to-Swift) would have to write custom binary conversion protocols just to pass a simple payload like username and email.

The Solution: A Universal Data Format

To bridge this gap, web architectures rely on a single, language-based intermediate format. The requirements for this format are simple:

  • Universal Parsing: Any language must be able to convert its native data into this format (serialize) and convert this format back into its native data (deserialize).
  • Text-Based: Easily sent over standard network protocols (like HTTP/HTTPS) without getting corrupted by system-level differences (such as big-endian vs. little-endian architecture).
  • Human-Readable: Developers must be able to open network tools, read the data, and debug requests easily without needing specialized binary decoders.

This is precisely where JSON steps in, acting as the common ground that allows entirely different tech stacks to communicate seamlessly.

What is JSON?

A JSON file is a lightweight, plain-text document used to store and organize structured data. It uses the .json file extension and follows the JavaScript Object Notation standard.

At its core, a JSON file is just a standard text file (like .txt). You can open, read, and edit it with any basic text editor (VS Code, Notepad, Vim).

File extension: .json (e.g., user_config.json, data.json) and MIME type: application/json (used in network headers). By default, JSON files are also encoded in UTF-8, allowing them to support multi-language characters and international data smoothly.

Inside a .json file, data is written using two fundamental structures:

  1. Key/Value Pairs (Objects): Wrapped in curly braces {}. Keys are always strings, followed by a colon ':‘, and then the value.
  2. Ordered Lists (Arrays): Wrapped in square brackets []. Values are separated by commas ‘,‘.

Example of a .json File (settings.json)

{
  "appName": "DevTracker",
  "version": 2.1,
  "isDarkModeEnabled": true,
  "maxProjectsAllowed": 10,
  "supportedLanguages": ["JavaScript", "Python", "Go"],
  "owner": {
    "name": "Alex",
    "email": "alex@example.com"
  },
  "backupSchedule": null
}

What are the data-types allowed in a JSON file?

Data TypeDescriptionExample
StringText wrapped in double quotes """Hello"
NumberInteger or floating-point number42 or 99.99
BooleanLogical true or falsetrue or false
ArrayAn ordered list of values["a", "b", "c"]
ObjectA collection of key/value pairs{"key": "value"}
NullRepresents an empty or nonexistent valuenull

Note: Functions/code, executable logic, comments (// or /* */), single quotes ('), or trailing commas after the last element are not allowed inside a JSON file. but, JSONC (JSON with Comments): Supported by VS Code (settings.json) and TypeScript config (tsconfig.json). Allows // and /* */ comments and JSON5: Expanded syntax that allows single quotes, trailing commas, multi-line strings, hex numbers, and unquoted keys for human-written config files.

Key Uses of JSON Files:

JSON files serve three major roles in modern computing:

A. Application Configuration

Many frameworks, tools, and environments use .json files to manage project settings because they are easy for both humans and scripts to read.

  • package.json in Node.js (manages dependencies and scripts).
  • tsconfig.json in TypeScript (defines compiler settings).
  • settings.json in editors like VS Code (stores user preferences).

B. Static Data Storage

Small datasets, seed data for databases, mock data for local testing, or internationalization (i18n) translation files are often saved as local .json files.

C. Offline Data Transfer

When APIs need to export bulk data (e.g., downloading your profile data from a web service), they frequently package and export it as a downloadable .json file.

Following snippets is how to read and write local .json files in various languages-

  • Python (json module): Python comes with a built-in json package. It uses json.load() to read from a file and json.dump() to write to a file.

Writing to a JSON File (write_example.py)

import json

# Python dictionary to save
data = {
    "appName": "DevTracker",
    "version": 2.1,
    "isDarkModeEnabled": True,  # Automatically converts to true in JSON
    "supportedLanguages": ["JavaScript", "Python", "Go"],
    "owner": {
        "name": "Alex",
        "email": "alex@example.com"
    }
}

# Write dictionary to data.json
# indent=4 formats the output with clean spacing (pretty-printing)
with open("data.json", "w", encoding="utf-8") as file:
    json.dump(data, file, indent=4)

print("data.json created successfully!")

Reading from a JSON File (read_example.py)

import json

# Read data.json into a Python dictionary
with open("data.json", "r", encoding="utf-8") as file:
    loaded_data = json.load(file)

# Accessing values like a standard dictionary
print("App Name:", loaded_data["appName"])
print("First Language:", loaded_data["supportedLanguages"][0])
print("Owner Email:", loaded_data["owner"]["email"])
  • JavaScript (Node.js fs module): In Node.js, you can use the built-in fs (File System) module with fs.promises or fs.readFileSync / fs.writeFileSync.

Writing to a JSON File (write_example.js)

const fs = require('fs/promises');

// JavaScript Object to save
const data = {
  appName: "DevTracker",
  version: 2.1,
  isDarkModeEnabled: true,
  supportedLanguages: ["JavaScript", "Python", "Go"],
  owner: {
    name: "Alex",
    email: "alex@example.com"
  }
};

async function writeJsonFile() {
  try {
    // 1. Convert JS Object to JSON String
    // null, 2 formats the file with 2 spaces of indentation
    const jsonString = JSON.stringify(data, null, 2);

    // 2. Write string to file
    await fs.writeFile('data.json', jsonString, 'utf-8');
    console.log('data.json created successfully!');
  } catch (error) {
    console.error('Error writing file:', error);
  }
}

writeJsonFile();

Reading from a JSON File (read_example.js), using fs.promises (Recommended for general data files)

const fs = require('fs/promises');

async function readJsonFile() {
  try {
    // 1. Read raw file contents as string
    const rawData = await fs.readFile('data.json', 'utf-8');

    // 2. Parse JSON String into a JavaScript Object
    const loadedData = JSON.parse(rawData);

    // Access values
    console.log("App Name:", loadedData.appName);
    console.log("First Language:", loadedData.supportedLanguages[0]);
    console.log("Owner Email:", loadedData.owner.email);
  } catch (error) {
    console.error('Error reading file:', error);
  }
}

readJsonFile();
  • PHP : PHP handles JSON natively using built-in functions like json_encode(), json_decode(), file_get_contents(), and file_put_contents().

Writing & Reading Example (index.php)

<?php
$filePath = 'data.json';

// 1. Prepare Data
$data = [
    "appName" => "DevTracker",
    "version" => 2.1,
    "supportedLanguages" => ["PHP", "Python", "JavaScript"]
];

// 2. WRITE to JSON file
// JSON_PRETTY_PRINT formats the output nicely
$jsonString = json_encode($data, JSON_PRETTY_PRINT);
file_put_contents($filePath, $jsonString);
echo "File written successfully!\n";

// 3. READ from JSON file
$rawJson = file_get_contents($filePath);

// Setting 2nd argument to true converts JSON into an associative array
$loadedData = json_decode($rawJson, true);

echo "App Name: " . $loadedData['appName'] . "\n";
echo "First Language: " . $loadedData['supportedLanguages'][0] . "\n";
?>
  • Go (Golang): Go uses its standard library package encoding/json combined with the os package.

Writing & Reading Example (main.go)

package main

import (
	"encoding/json"
	"fmt"
	"os"
)

// Define a struct matching the JSON structure
type Config struct {
	AppName            string   `json:"appName"`
	Version            float64  `json:"version"`
	SupportedLanguages []string `json:"supportedLanguages"`
}

func main() {
	filePath := "data.json"

	data := Config{
		AppName:            "DevTracker",
		Version:            2.1,
		SupportedLanguages: []string{"Go", "Python", "JavaScript"},
	}

	// 1. WRITE to JSON file
	// MarshalIndent converts struct to formatted JSON bytes
	jsonBytes, _ := json.MarshalIndent(data, "", "  ")
	_ = os.WriteFile(filePath, jsonBytes, 0644)
	fmt.Println("File written successfully!")

	// 2. READ from JSON file
	fileBytes, _ := os.ReadFile(filePath)
	var loadedData Config

	// Unmarshal converts JSON bytes back into Go struct
	_ = json.Unmarshal(fileBytes, &loadedData)
	fmt.Println("App Name:", loadedData.AppName)
	fmt.Println("First Language:", loadedData.SupportedLanguages[0])
}
  • C# (.NET): Modern .NET includes high-performance built-in JSON support via System.Text.Json.

Writing & Reading Example (Program.cs)

using System;
using System.IO;
using System.Text.Json;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        string filePath = "data.json";

        var data = new
        {
            appName = "DevTracker",
            version = 2.1,
            supportedLanguages = new List<string> { "C#", "Python", "JavaScript" }
        };

        // 1. WRITE to JSON file
        var options = new JsonSerializerOptions { WriteIndented = true };
        string jsonString = JsonSerializer.Serialize(data, options);
        File.WriteAllText(filePath, jsonString);
        Console.WriteLine("File written successfully!");

        // 2. READ from JSON file
        string readJsonString = File.ReadAllText(filePath);
        using JsonDocument doc = JsonDocument.Parse(readJsonString);
        
        JsonElement root = doc.RootElement;
        Console.WriteLine($"App Name: {root.GetProperty("appName").GetString()}");
    }
}

Note: In dynamic languages like JavaScript or Python, parsing JSON feels almost invisible. A JSON string becomes a flexible JavaScript object or Python dictionary, allowing you to access properties on the fly without declaring what shape the data should take. However, in strongly typed enterprise languages like Go, C# etc, every variable must have an explicit data type defined at compile time. These languages cannot simply receive arbitrary JSON without knowing its structure in advance.

Instead, they map incoming JSON payloads directly to Structs or Classes through a process called Data Binding (or Schema Unmarshalling).

How do backends validate incoming JSON before touching the database? JSON Schema.

Accepting arbitrary JSON from external users or third-party APIs can be risky. If an incoming request is missing a mandatory email key or sends an age of -50 as a string instead of a positive integer, your backend software might crash or pollute your database.

To prevent this, applications rely on data validation schemas, blueprints that define the precise shape, required keys, data types, and value limits of expected JSON.

What is JSON Schema?

JSON Schema is a vocabulary that allows you to annotate and validate JSON documents. Think of it as a strict contract or blueprint for your data structure.

A JSON Schema specifies – What data types each value must have (string, integer, boolean, etc.), which keys must be present (required fields), value constraints (minimum/maximum limits, regex string patterns, array lengths) and default fallback values.

An Example: JSON Schema

Here is how you write a official standard JSON Schema blueprint to validate a user registration payload:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "minLength": 3
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "age": {
      "type": "integer",
      "minimum": 18,
      "maximum": 120
    }
  },
  "required": ["username", "email", "age"],
  "additionalProperties": false
}

What this Schema Enforces?

  1. Required Fields: The JSON object must contain username, email, and age.
  2. Email Format: The email field must follow a valid email string format.
  3. Age Constraints: The age field must be an integer between 18 and 120.
  4. No Extra Keys: "additionalProperties": false rejects any unexpected fields sent by the client.

JSON Security Pitfalls: Mass Assignment & JSON Injection

Because JSON is plain text and easily mapped directly into application logic or database models, it introduces security vulnerabilities if handled carelessly. When receiving JSON from unauthenticated or untrusted users, developers must guard against two major security pitfalls: Mass Assignment and JSON Injection.

  • Mass Assignment (Over-Posting)

Mass Assignment occurs when a framework automatically binds an incoming JSON payload directly to an internal data model or database record without filtering which fields the user is allowed to update.

How the Attack Works:

Imagine a user updating their profile details (bio and username). The application receives this standard update request:

{
  "bio": "Full-stack developer building cool apps.",
  "location": "Kolkata"
}

If the backend takes the entire JSON object and passes it straight into an ORM update query (e.g., User.update(request.json)), a malicious user can inspect the network request and inject unexpected administrative fields into the payload:

{
  "bio": "Full-stack developer building cool apps.",
  "location": "Kolkata",
  "role": "admin",
  "isVerified": true,
  "accountBalance": 999999
}

Because the backend blindly updates all keys matching the database schema, the attacker just elevated their privilege level to administrator simply by adding "role": "admin" to their JSON payload.

Prevention: Never bind raw JSON directly to database models. Use Data Transfer Objects (DTOs), explicit field whitelists, or validation schemas (like Zod or Pydantic) to strictly define allowed input fields before processing.

  • JSON Injection

JSON Injection happens when an application constructs JSON strings by concatenating un-sanitized user input rather than using a proper native serialization function (JSON.stringify() or json.dumps()).

How the Attack Works:

Suppose a backend manually creates a JSON response using string concatenation:

// BAD: Manual string concatenation with user input
const userRole = getUserRoleInput(); // User inputs: user" }, "role": "admin", "x": "
const responseJson = `{"user": "${userRole}", "status": "active"}`;

If the attacker crafts their input string carefully, they can break out of the intended key/value structure and inject new parameters:

Resulting concatenated string:
{"user": "user" }, "role": "admin", "x": "", "status": "active"}

When this string is later parsed down the line, the injected "role": "admin" key can override security logic.

Prevention: Never manually concatenate JSON strings. Always construct native data objects in your programming language first, then serialize them using standard built-in functions.

The Pros & Cons of JSON

While JSON is the undisputed standard for modern web applications, no technology is a one-size-fits-all solution. Understanding its strengths and limitations will help you decide when to use JSON and when an alternative format might be better suited.

Advantages of JSON

1. Highly Readable & Intuitive

JSON’s clean key/value syntax closely mimics natural data representation in modern programming languages. Unlike XML or binary formats, human developers can open a raw .json file and immediately understand its structure without specialized decoding tools.

2. Lightweight with Minimal Overhead

JSON does not rely on verbose closing tags (e.g., <user><name>Alex</name></user>). Its compact syntax reduces payload sizes significantly, saving bandwidth and lowering latency over network connections.

3. Native Compatibility with JavaScript

Because JSON is derived directly from JavaScript object literal syntax, web browsers can parse and serialize it natively without requiring external libraries or heavy processing pipelines.

4. Language-Agnostic Ecosystem

Virtually every major programming language like Python, Java, Go, C#, PHP, Rust, has native or standard library support for JSON serialization and deserialization, making it an ideal intermediate medium for cross-stack communication.

5. Native Database Support

Modern database engines including NoSQL databases like MongoDB (which uses BSON, a binary variant of JSON) and relational databases like PostgreSQL and MySQL, support JSON columns natively, allowing you to query nested JSON fields directly using SQL.

Disadvantages & Limitations of JSON

1. Verbose for High-Frequency Big Data

While JSON is lighter than XML, it is still a text-based format. Sending large datasets repeatedly over network sockets transfers key names over and over again ("username": "a", "username": "b"). For high-performance microservices, binary protocols like Protocol Buffers (Protobuf) or MessagePack offer up to 6–10× faster transfer speeds.

2. Restricted Data Types and Strict Syntax Standard

JSON only supports six basic data types (String, Number, Boolean, Array, Object, Null). JSON is notoriously unforgiving of minor syntax errors: It lacks native representation for:

  • Dates/Time: Must be sent as ISO strings (e.g., "2026-08-05T20:21:00Z") or epoch timestamps.
  • Binary Data: Images or file buffers must be converted to Base64 strings, increasing file sizes by ~33%.
  • Exact Precision Decimals: Large numeric values can suffer from IEEE-754 floating-point precision loss during parsing.
  • Comments (// or /* */) are forbidden.
  • Trailing commas ({"a": 1,}) break parsers completely.
  • Single quotes ('key') trigger fatal syntax errors.

3. Large File Size & Bandwidth Waste (Redundant Keys)

Because JSON is plain text and self-describing, field names are repeated for every single object in an array.

In massive datasets containing thousands of records, repeating verbose key names like "customerAccountBalanceNumber" consumes significant network bandwidth. Formats like CSV or binary protocols specify column/field names once in a header/schema, drastically reducing payload size.

4. High CPU & Memory Overhead for Parsing

Parsing a JSON document requires scanning text character-by-character to validate syntax, construct objects, and allocate memory.

Converting a multi-megabyte JSON string into native language objects strains CPU and RAM, especially on resource-constrained devices like smartphones or IoT sensors, so the alternative is zero-copy binary serialization formats (like FlatBuffers or Cap’n Proto) allow applications to access data fields directly in memory without executing a costly deserialization parsing step.

5. Limited Number Precision & Risk of Data Loss

JSON specifies numbers as standard numeric literals without distinguishing between integers, floats, or high-precision decimals.

Most JavaScript environments parse numbers as IEEE-754 double-precision floats. Numbers larger than 253 – 1 (like 64-bit database IDs e.g., 9007199254740993) lose precision when parsed in JS. The solution is backend developers are forced to serialize large 64-bit integers or exact financial decimals as strings ("9007199254740993"), bypassing JSON’s native number support entirely to avoid data corruption.

6. Inefficient for Binary Media Transmission

If your web application needs to send image data, audio files, or raw PDF buffers alongside structured data over JSON, it faces a major performance penalty. Since JSON is strictly text-based, binary bytes must be encoded into Base64 strings. With result being, base64 encoding inflates raw file sizes by roughly 33%, increasing network load. Formats like BSON or Multipart Form-Data stream raw binary bytes without size inflation.

7. No Built-In Namespace Support

Unlike XML (which features XML Namespaces xmlns to merge data from multiple domain sources without key name collisions), JSON has no native concept of namespaces. If you merge multiple JSON data streams, identical key names (like "id" or "type") will collide or overwrite each other unless developers manually prefix keys (e.g., "user_id" vs "order_id").

Over two decades after its creation, JSON remains the foundational medium for web data exchange. It successfully solved one of software engineering’s hardest communication challenges: getting vastly different technology stacks to talk to one another over a network without friction or heavy parsing overhead. By striking the ideal balance between human readability for developers and machine efficiency for computers, JSON effectively displaced XML and became the default standard for Document-oriented databases like MongoDB, RESTful APIs and modern web services and Configuration management across developer toolchains (package.json, tsconfig.json).

Thanks for sticking around! Here’s hoping your next data exchange is seamless, swift, and entirely exception-free.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top