Documentation Index
Fetch the complete documentation index at: https://soul-lang.com/llms.txt
Use this file to discover all available pages before exploring further.
JSON
The JSON module provides comprehensive JSON (JavaScript Object Notation) capabilities for Soul, including parsing, serialization, and validation. It offers both Soul-style and JavaScript-style aliases for familiar API usage.
Parsing JSON
decode / parse - Parse JSON string to object
Parse a JSON string into Soul objects (maps or lists):
// Using decode (Soul-style)
jsonString = '{"name": "Alice", "age": 30, "active": true}'
data = JSON.decode(jsonString)
println(data.name) // "Alice"
println(data.age) // 30
println(data.active) // true
// Using parse (JavaScript-style alias)
arrayJson = '[1, 2, 3, 4, 5]'
numbers = JSON.parse(arrayJson)
println(numbers) // [1, 2, 3, 4, 5]
Parsing Complex Structures
Parse nested JSON structures:
complexJson = '{
"user": {
"id": 123,
"profile": {
"name": "Bob",
"email": "bob@example.com"
}
},
"scores": [85, 92, 78],
"active": true
}'
data = JSON.decode(complexJson)
println(data.user.profile.name) // "Bob"
println(data.scores[1]) // 92
Serialization
encode / stringify - Convert object to JSON string
Convert Soul objects (maps or lists) to JSON strings:
// Using encode (Soul-style)
user = {
name: "Charlie",
age: 25,
hobbies: ["reading", "gaming", "coding"]
}
jsonString = JSON.encode(user)
println(jsonString) // {"age":25,"hobbies":["reading","gaming","coding"],"name":"Charlie"}
// Using stringify (JavaScript-style alias)
numbers = [1, 2, 3, 4, 5]
jsonArray = JSON.stringify(numbers)
println(jsonArray) // [1,2,3,4,5]
Serializing Complex Objects
Serialize nested structures:
data = {
timestamp: "2024-01-01T12:00:00Z",
metrics: {
cpu: 45.5,
memory: 78.2,
disk: 60.0
},
tags: ["production", "server-01"],
healthy: true
}
jsonOutput = JSON.encode(data)
println(jsonOutput)
// {"healthy":true,"metrics":{"cpu":45.5,"disk":60,"memory":78.2},"tags":["production","server-01"],"timestamp":"2024-01-01T12:00:00Z"}
Validation
isValid - Check if string is valid JSON
Validate whether a string contains valid JSON:
// Valid JSON
validJson = '{"key": "value"}'
isValid = JSON.isValid(validJson)
println(isValid) // true
// Invalid JSON
invalidJson = '{key: value}' // Missing quotes
isValid = JSON.isValid(invalidJson)
println(isValid) // false
// Empty string
isValid = JSON.isValid("")
println(isValid) // false
// Valid array JSON
arrayJson = '[1, 2, 3]'
isValid = JSON.isValid(arrayJson)
println(isValid) // true
Data Type Handling
Supported Data Types
The JSON module handles all standard JSON data types:
// All JSON data types
data = {
string: "Hello, World!",
number: 42.5,
integer: 100,
boolean: true,
null: null,
array: [1, "two", 3.0, false],
object: {
nested: "value"
}
}
// Encode to JSON
json = JSON.encode(data)
// Decode back
decoded = JSON.decode(json)
println(decoded.string) // "Hello, World!"
println(decoded.number) // 42.5
println(decoded.boolean) // true
println(decoded.null) // null
Map Key Conversion
When encoding maps, different key types are converted to strings:
// String keys (standard)
stringMap = {
"key1": "value1",
"key2": "value2"
}
// Number keys (converted to strings)
numberMap = {
1: "first",
2: "second"
}
// Boolean keys (converted to strings)
boolMap = {
true: "yes",
false: "no"
}
println(JSON.encode(stringMap)) // {"key1":"value1","key2":"value2"}
println(JSON.encode(numberMap)) // {"1":"first","2":"second"}
println(JSON.encode(boolMap)) // {"false":"no","true":"yes"}
Error Handling
Parsing Errors
Handle JSON parsing errors gracefully:
soul safeJsonParse(jsonString) {
result = JSON.decode(jsonString)
// Check if result is an error
if (result.type() == "ERROR") {
println("Failed to parse JSON: " + result)
return null
}
return result
}
// Test with invalid JSON
invalidJson = '{"name": "Alice", "age": }' // Invalid - missing value
parsed = safeJsonParse(invalidJson)
if (parsed == null) {
println("Handling invalid JSON...")
}
Encoding Errors
Handle encoding errors for unsupported types:
soul safeJsonEncode(data) {
result = JSON.encode(data)
if (result.type() == "ERROR") {
println("Failed to encode JSON: " + result)
return null
}
return result
}
// Only LIST and MAP types can be encoded
validData = {key: "value"}
encoded = safeJsonEncode(validData)
println(encoded) // {"key":"value"}
Practical Examples
Configuration File Handling
soul loadConfig(filename) {
// Read JSON configuration file
content = File.read(filename)
if (!JSON.isValid(content)) {
println("Invalid configuration file")
return null
}
config = JSON.decode(content)
return config
}
soul saveConfig(config, filename) {
// Serialize configuration to JSON
jsonContent = JSON.encode(config)
File.write(filename, jsonContent)
return true
}
// Usage
config = {
server: {
host: "localhost",
port: 8080,
ssl: false
},
database: {
url: "postgres://localhost/mydb",
pool_size: 10
},
features: ["auth", "api", "websocket"]
}
saveConfig(config, "app.config.json")
loaded = loadConfig("app.config.json")
API Response Handling
soul parseApiResponse(responseBody) {
// Validate response
if (!JSON.isValid(responseBody)) {
return {
success: false,
error: "Invalid JSON response"
}
}
// Parse response
data = JSON.decode(responseBody)
// Process based on structure
if (data.status == "success") {
return {
success: true,
data: data.result
}
} else {
return {
success: false,
error: data.message || "Unknown error"
}
}
}
// Example API response
apiResponse = '{"status": "success", "result": {"id": 123, "name": "Product"}}'
result = parseApiResponse(apiResponse)
if (result.success) {
println("Got data: " + JSON.encode(result.data))
}
soul transformJsonData(jsonInput) {
// Parse input
data = JSON.decode(jsonInput)
// Transform data
transformed = {
id: data.id,
fullName: data.firstName + " " + data.lastName,
email: data.email.toLowerCase(),
active: data.status == "active",
metadata: {
created: data.createdAt,
updated: Date.now(),
version: 2
}
}
// Return as JSON
return JSON.encode(transformed)
}
// Input JSON
input = '{
"id": 456,
"firstName": "John",
"lastName": "Doe",
"email": "JOHN.DOE@EXAMPLE.COM",
"status": "active",
"createdAt": "2024-01-01"
}'
output = transformJsonData(input)
println(output)
Working with JSON Arrays
soul processJsonArray(jsonArray) {
// Parse JSON array
items = JSON.decode(jsonArray)
// Process each item
processed = Array.map(items, soul(item) {
return {
id: item.id,
name: item.name.toUpperCase(),
value: item.price * item.quantity
}
})
// Calculate totals
total = Array.reduce(processed, soul(sum, item) {
return sum + item.value
}, 0)
// Return result as JSON
result = {
items: processed,
total: total,
count: Array.length(processed)
}
return JSON.encode(result)
}
// Example usage
products = '[
{"id": 1, "name": "Apple", "price": 0.5, "quantity": 10},
{"id": 2, "name": "Banana", "price": 0.3, "quantity": 15},
{"id": 3, "name": "Orange", "price": 0.7, "quantity": 8}
]'
result = processJsonArray(products)
println(result)
JSON Validation Workflow
soul validateJsonSchema(json, requiredFields) {
// First check if valid JSON
if (!JSON.isValid(json)) {
return {valid: false, error: "Invalid JSON format"}
}
// Parse JSON
data = JSON.decode(json)
// Check if it's an object (map)
if (data.type() != "MAP") {
return {valid: false, error: "JSON must be an object"}
}
// Validate required fields
missing = []
Array.forEach(requiredFields, soul(field) {
if (!data.hasKey(field)) {
Array.push(missing, field)
}
})
if (Array.length(missing) > 0) {
return {
valid: false,
error: "Missing required fields: " + Array.join(missing, ", ")
}
}
return {valid: true, data: data}
}
// Test validation
userJson = '{"name": "Alice", "email": "alice@example.com"}'
required = ["name", "email", "age"]
validation = validateJsonSchema(userJson, required)
if (!validation.valid) {
println("Validation failed: " + validation.error)
}
Best Practices
- Always validate before parsing: Use
isValid() to check JSON validity before parsing
- Handle errors gracefully: Check for ERROR types when parsing or encoding
- Use appropriate aliases: Choose
decode/encode or parse/stringify based on your preference
- Be aware of type limitations: Only LIST and MAP types can be encoded to JSON
- Consider memory usage: Large JSON strings can consume significant memory
// Good - validate before parsing
soul parseJsonSafely(jsonString) {
if (!JSON.isValid(jsonString)) {
return null
}
return JSON.decode(jsonString)
}
// Good - handle different input types
soul toJson(data) {
type = data.type()
if (type != "LIST" && type != "MAP") {
// Wrap in a map if not directly serializable
return JSON.encode({value: data})
}
return JSON.encode(data)
}
// Good - parse with default values
soul parseWithDefaults(jsonString, defaults) {
if (!JSON.isValid(jsonString)) {
return defaults
}
parsed = JSON.decode(jsonString)
// Merge with defaults
result = {}
for (key in defaults) {
result[key] = parsed[key] || defaults[key]
}
return result
}
The JSON module provides essential tools for working with JSON data in Soul, enabling seamless integration with APIs, configuration files, and data exchange formats commonly used in modern applications.