Mojo JSON Handling
JSON (JavaScript Object Notation) is the most widely used format for exchanging data between programs, APIs, and configuration files. It is human-readable, language-neutral, and supported everywhere. Mojo handles JSON through Python's built-in json module via the interop layer, giving you full parsing and generation capability.
What JSON Looks Like
{
"name": "Alice",
"age": 30,
"active": true,
"scores": [95, 87, 91],
"address": {
"city": "Tokyo",
"country": "Japan"
},
"notes": null
}
JSON data types:
┌────────────┬──────────────────────────┐
│ JSON │ Python (via interop) │
├────────────┼──────────────────────────┤
│ string │ str │
│ number │ int or float │
│ boolean │ True / False │
│ null │ None │
│ array │ list │
│ object │ dict │
└────────────┴──────────────────────────┘
Parsing JSON: json.loads
from python import Python
fn main() raises:
var json = Python.import_module("json")
var raw = '{"name": "Alice", "age": 30, "scores": [95, 87, 91]}'
var data = json.loads(raw) # JSON string → Python dict
print(data["name"]) # Alice
print(data["age"]) # 30
print(data["scores"][0]) # 95
print(data["scores"][1]) # 87
json.loads() flow:
JSON string: '{"name": "Alice", "age": 30}'
│
▼ json.loads()
Python dict: {"name": "Alice", "age": 30}
│
Access with ["key"] just like a regular dict
Generating JSON: json.dumps
from python import Python
fn main() raises:
var json = Python.import_module("json")
var py = Python.import_module("builtins")
# Build a Python dict from scratch
var data = py.dict()
data["product"] = "Mojo Compiler"
data["version"] = 1
data["stable"] = True
data["features"] = py.list(["SIMD", "parallelism", "ownership"])
# Convert to JSON string
var json_str = json.dumps(data, indent=2)
print(json_str)
Output:
{
"product": "Mojo Compiler",
"version": 1,
"stable": true,
"features": [
"SIMD",
"parallelism",
"ownership"
]
}
Reading JSON from a File
from python import Python
fn main() raises:
var json = Python.import_module("json")
# Write a sample JSON file first
with open("config.json", "w") as f:
f.write('{"host": "localhost", "port": 8080, "debug": true}')
# Read and parse it
var py_open = Python.import_module("builtins").open
var file = py_open("config.json", "r")
var config = json.load(file) # parse from file object directly
file.close()
print(config["host"]) # localhost
print(config["port"]) # 8080
print(config["debug"]) # True
Writing JSON to a File
from python import Python
fn main() raises:
var json = Python.import_module("json")
var py = Python.import_module("builtins")
var results = py.list()
for i in range(5):
var entry = py.dict()
entry["id"] = i
entry["score"] = 80 + i * 4
results.append(entry)
# Write to file with pretty formatting
var outfile = py.open("results.json", "w")
json.dump(results, outfile, indent=2)
outfile.close()
print("Saved results.json")
Output file:
[
{"id": 0, "score": 80},
{"id": 1, "score": 84},
{"id": 2, "score": 88},
{"id": 3, "score": 92},
{"id": 4, "score": 96}
]
Navigating Nested JSON
from python import Python
fn main() raises:
var json = Python.import_module("json")
var raw = """
{
"company": "Modular",
"language": {
"name": "Mojo",
"version": 1,
"targets": ["CPU", "GPU", "TPU"]
}
}
"""
var d = json.loads(raw)
# Navigate nested structure
print(d["company"]) # Modular
print(d["language"]["name"]) # Mojo
print(d["language"]["targets"][0]) # CPU
print(d["language"]["targets"][1]) # GPU
Nested access diagram:
d
├── "company" → "Modular"
└── "language"
├── "name" → "Mojo"
├── "version" → 1
└── "targets" → ["CPU", "GPU", "TPU"]
↑ ↑
[0] [1]
Handling Missing Keys Safely
from python import Python
fn main() raises:
var json = Python.import_module("json")
var raw = '{"name": "Bob", "age": 25}'
var data = json.loads(raw)
# Use .get() with a default to avoid KeyError
var name = str(data.get("name", "Unknown"))
var email = str(data.get("email", "not provided"))
var country = str(data.get("country", "not provided"))
print("Name:", name) # Name: Bob
print("Email:", email) # Email: not provided
print("Country:", country) # Country: not provided
JSON API Response Pattern
from python import Python
fn fetch_and_parse(url: String) raises -> PythonObject:
var requests = Python.import_module("requests")
var json = Python.import_module("json")
var response = requests.get(url)
if int(response.status_code) != 200:
raise Error("HTTP error: " + str(response.status_code))
return json.loads(str(response.text))
fn main() raises:
# Example with a public API
try:
var data = fetch_and_parse("https://api.github.com/repos/modularml/mojo")
print("Stars:", data["stargazers_count"])
print("Forks:", data["forks_count"])
print("Language:", data["language"])
except e:
print("API request failed:", str(e))
json.dumps Options
Option | Effect
----------------------|-------------------------------------------
indent=2 | Pretty-print with 2-space indentation
sort_keys=True | Sort dictionary keys alphabetically
ensure_ascii=False | Allow non-ASCII characters (e.g. emoji)
separators=(","," :") | Compact format, no extra spaces
Examples:
json.dumps(d, indent=4) → nicely indented
json.dumps(d, sort_keys=True) → keys in A-Z order
json.dumps(d, separators=(",",":") → minimal whitespace
Key Takeaways
Import Python's json module with Python.import_module("json"). Parse a JSON string with json.loads(text) to get a Python dict or list. Convert a Python object back to JSON with json.dumps(obj, indent=2). Read directly from a file object with json.load(file) and write with json.dump(obj, file). Navigate nested structures by chaining bracket access. Use .get(key, default) to safely access keys that might be absent. The indent, sort_keys, and ensure_ascii options control output formatting.
