Skip to main content

JSON & Serialization

JSON is the most common data exchange format. Here's how different languages handle JSON parsing and serialization.

Parsing & Serializing JSON​

// Parse JSON string to object
const data = JSON.parse('{"name":"John","age":30}');
console.log(data.name); // "John"

// Serialize object to JSON string
const json = JSON.stringify({ name: "John", age: 30 });
// '{"name":"John","age":30}'

// Pretty print
const pretty = JSON.stringify(data, null, 2);

// Custom serialization (replacer)
const json2 = JSON.stringify(data, (key, value) => {
if (key === "age") return undefined; // Exclude
return value;
});

// Parse with reviver
const data2 = JSON.parse(json, (key, value) => {
if (key === "date") return new Date(value);
return value;
});

// Fetch JSON from API
const response = await fetch('/api/data');
const apiData = await response.json();

Key Takeaways​

  • Built-in vs library support — JavaScript (JSON.parse/JSON.stringify), Python (json module), PHP (json_decode/json_encode), and Ruby (JSON.parse/to_json) include JSON in the standard library. Rust uses the serde + serde_json crates; Go uses encoding/json; C and C++ require external libraries like cJSON or nlohmann/json. For web APIs and config parsing, built-in support is convenient; for embedded or systems work, factor in the dependency and build size of JSON libraries.

  • Typed deserialization — Rust's serde maps JSON to structs with #[derive(Deserialize)]; Go uses struct tags: type Person struct { Name string \json:"name"` }; Swift's Codableand C#'sSystem.Text.Jsondo the same. When you need to work with unknown structure, use dynamic types:serde_json::Value, map[string]interface, JsonNode, or JsonDocument`. Prefer typed deserialization for internal APIs and configs; use dynamic parsing when the schema is flexible or externally controlled.

  • Derive/Codable patterns — Rust's #[derive(Serialize, Deserialize)], Swift's Codable, and C#'s record types enable automatic serialization with minimal boilerplate. You define the struct and get JSON round-trip for free; custom serialization uses Serialize/Deserialize implementations or attributes like #[serde(rename = "first_name")]. This reduces boilerplate and keeps schema and code in sync. For new projects, prefer languages with strong derive/Codable support; avoid manual marshalling unless you need custom logic.

  • Custom serialization and edge cases — Python's JSONEncoder and JavaScript's replacer/reviver allow custom handling of dates, BigInt, or other non-JSON types. Go's encoding/json requires custom MarshalJSON/UnmarshalJSON for non-standard types. Rust's serde supports #[serde(serialize_with = "...")] for custom logic. When dealing with dates, decimals, or special types, check the library's customization options; JavaScript and Python offer flexible hooks, while Go and Rust require more explicit implementations.