JSON Support in GoloScript

This comprehensive guide explains how to use JSON support in GoloScript, including the toJSON(), fromJSON(), and escapeJSON() functions.

Introduction

GoloScript provides native and comprehensive JSON support that allows you to:

JSON support automatically handles all Golo types (numbers, strings, booleans, null, arrays, maps, DynamicObjects) as well as complex nested structures.

Available Functions

toJSON(value)

Converts a Golo value to a JSON string.

let num = 42
let json = toJSON(num)  # "42"

let obj = map[["name", "Alice"], ["age", 30]]
let json = toJSON(obj)  # {"age":30,"name":"Alice"}

fromJSON(jsonString)

Parses a JSON string and returns a Golo object.

let json = "{\"name\":\"Bob\",\"age\":25}"
let obj = fromJSON(json)
println(obj: name())  # Bob
println(obj: age())   # 25

escapeJSON(string)

Manually escapes a string for use in JSON (newlines, quotes, etc.).

let text = """Line 1
Line 2"""
let escaped = escapeJSON(text)  # "Line 1\nLine 2"

Note: toJSON() does this escaping automatically. Only use escapeJSON() when manually constructing JSON via templates.

Basic Usage

Encoding Simple Values

# Numbers
toJSON(42)        # 42
toJSON(3.14)      # 3.14
toJSON(-100)      # -100

# Strings
toJSON("Hello")   # "Hello"
toJSON("")        # ""

# Booleans and null
toJSON(true)      # true
toJSON(false)     # false
toJSON(null)      # null

Encoding Collections

# Simple array
let arr = [1, 2, 3, 4, 5]
toJSON(arr)  # [1,2,3,4,5]

# Mixed type array
let mixed = [1, "hello", true, null, 3.14]
toJSON(mixed)  # [1,"hello",true,null,3.14]

# Nested array
let nested = [[1, 2], [3, 4], [5, 6]]
toJSON(nested)  # [[1,2],[3,4],[5,6]]

Encoding Objects

# Map
let person = map[["name", "Alice"], ["age", 30], ["city", "Paris"]]
toJSON(person)  # {"age":30,"city":"Paris","name":"Alice"}

# DynamicObject
let obj = DynamicObject()
  : name("Bob")
  : age(25)
  : active(true)
toJSON(obj)  # {"active":true,"age":25,"name":"Bob"}

Decoding JSON

# Parse a number
let num = fromJSON("42")  # 42

# Parse an array
let arr = fromJSON("[1,2,3]")  # [1, 2, 3]

# Parse an object
let obj = fromJSON("{\"name\":\"Alice\",\"age\":30}")
println(obj: name())  # Alice
println(obj: age())   # 30

Round-trip (Encode then Decode)

# Create an object
let original = map[["title", "Golo"], ["version", 2.0]]

# Encode to JSON
let json = toJSON(original)  # {"title":"Golo","version":2.0}

# Decode
let decoded = fromJSON(json)
println(decoded: title())    # Golo
println(decoded: version())  # 2.0

Supported Types

Primitive Types

Golo Type JSON Type Example
Integer number 42 β†’ 42
Float number 3.14 β†’ 3.14
String string "hello" β†’ "hello"
Boolean boolean true β†’ true
null null null β†’ null

Collections

Golo Type JSON Type Example
Array array [1, 2, 3] β†’ [1,2,3]
Map object map[["a", 1]] β†’ {"a":1}
DynamicObject object obj:a(1) β†’ {"a":1}

Nested Structures

GoloScript handles complex nested structures perfectly:

let config = DynamicObject()
  : appName("MyApp")
  : version("1.0.0")
  : settings(DynamicObject()
      : debug(true)
      : port(8080)
  )
  : servers(["server1.com", "server2.com"])

toJSON(config)
# {"appName":"MyApp","servers":["server1.com","server2.com"],"settings":{"debug":true,"port":8080},"version":"1.0.0"}

Advanced Cases

Multiline Strings

toJSON() automatically handles multiline strings by escaping them correctly:

let poem = """Roses are red,
Violets are blue,
Golo is great!"""

toJSON(poem)  # "Roses are red,\nViolets are blue,\nGolo is great!"

# Round-trip preserves the original content
let decoded = fromJSON(toJSON(poem))
println(decoded)  # Displays the poem on 3 lines

Strings with Special Characters

let text = "He said \"Hello!\" to her"
toJSON(text)  # "He said \"Hello!\" to her"

let special = "Tabs:\t\tNewlines:\n"
toJSON(special)  # "Tabs:\t\tNewlines:\n"

Unicode Characters

let unicode = "Hello δΈ–η•Œ 🌍"
toJSON(unicode)  # "Hello δΈ–η•Œ 🌍"

Array of Objects

let users = [
  map[["id", 1], ["name", "Alice"]],
  map[["id", 2], ["name", "Bob"]],
  map[["id", 3], ["name", "Charlie"]]
]

let json = toJSON(users)
# [{"id":1,"name":"Alice"},{"id":2,"name":"Bob"},{"id":3,"name":"Charlie"}]

let decoded = fromJSON(json)
println(decoded: get(0): name())  # Alice

Template vs toJSON

There are two approaches to building JSON in GoloScript.

❌ Problem: Template without Escaping

let systemMsg = """You are a helpful assistant.
You can say "Hello!" """

let badTemplate = """{"message": "{{.Msg}}"}"""
let badData = DynamicObject(): Msg(systemMsg)
let badJSON = template(badTemplate, badData)
# ⚠️ BROKEN: Newlines and quotes are not escaped!

βœ… Solution 1: Template + escapeJSON()

import nova.Helpers

let goodData = DynamicObject(): Msg(escapeJSON(systemMsg))
let goodJSON = template(badTemplate, goodData)
# βœ“ VALID: String is properly escaped

Advantages:

Disadvantages:

βœ… Solution 2: toJSON() (Recommended)

let request = DynamicObject()
  : model("gpt-3.5")
  : message(systemMsg)  # ← No escaping needed!

let json = toJSON(request)
# βœ“ VALID: Automatic escaping

Advantages:

Disadvantages:

Recommendations

Use TEMPLATE + escapeJSON() when:

Use toJSON() when:

πŸ’‘ General guideline: For new code, prefer toJSON() for better safety and maintainability, especially for API requests.

Practical Examples

Example 1: Application Configuration

let config = DynamicObject()
  : appName("MyGoloApp")
  : version("1.0.0")
  : database(DynamicObject()
      : host("localhost")
      : port(5432)
      : name("mydb")
  )
  : features(["auth", "logging", "metrics"])
  : debug(true)

# Save to JSON
let configJSON = toJSON(config)
writeFile("config.json", configJSON)

# Load from JSON
let loadedConfig = fromJSON(readFile("config.json"))
println(loadedConfig: database(): host())  # localhost

Example 2: AI API Request

let buildAIRequest = |model, systemPrompt, userMessage| {
  return DynamicObject()
    : model(model)
    : temperature(0.7)
    : messages([
        DynamicObject(): role("system"): content(systemPrompt),
        DynamicObject(): role("user"): content(userMessage)
    ])
    : stream(false)
}

let systemPrompt = """You are a helpful coding assistant.
You can answer questions about programming.
Always provide clear examples."""

let request = buildAIRequest(
  "gpt-4",
  systemPrompt,
  "How do I use JSON in Golo?"
)

let requestJSON = toJSON(request)
# Send via HTTP...

Example 3: Structured Data for REST API

let createUserPayload = |name, email, roles| {
  return DynamicObject()
    : name(name)
    : email(email)
    : roles(roles)
    : active(true)
    : metadata(DynamicObject()
        : createdAt(nowAsISO())
        : source("api")
    )
}

let newUser = createUserPayload(
  "Alice Johnson",
  "alice@example.com",
  ["user", "editor"]
)

let payload = toJSON(newUser)
# POST to /api/users with payload

Example 4: Parse API Response

let responseJSON = """
{
  "status": "success",
  "data": {
    "users": [
      {"id": 1, "name": "Alice", "active": true},
      {"id": 2, "name": "Bob", "active": false}
    ],
    "total": 2
  }
}
"""

let response = fromJSON(responseJSON)
println("Status:", response: status())
println("Total:", response: data(): total())

# Iterate over users
let users = response: data(): users()
foreach user in users {
  println("User:", user: name(), "- Active:", user: active())
}

Best Practices

βœ… Do

  1. Use toJSON() for new code

    let data = DynamicObject(): name("Alice"): age(30)
    let json = toJSON(data)  # Safe and automatic
    
  2. Check values after fromJSON()

    let obj = fromJSON(jsonString)
    if obj: isNotNull() {
      println(obj: name())
    }
    
  3. Use helper functions for common structures

    function createAPIRequest = |endpoint, method, body| {
      return DynamicObject()
        : endpoint(endpoint)
        : method(method)
        : body(body)
    }
    
  4. Handle parsing errors

    try {
      let obj = fromJSON(jsonString)
      # Use obj...
    } catch (e) {
      println("JSON parsing error:", e: getMessage())
    }
    

❌ Don’t

  1. Don’t forget to escape with templates

    # ❌ Bad
    let data = DynamicObject(): msg(multilineText)
    let json = template(tpl, data)  # Broken if multilineText has newlines!
    
    # βœ… Good
    let data = DynamicObject(): msg(escapeJSON(multilineText))
    let json = template(tpl, data)
    
    # βœ…βœ… Even better
    let obj = DynamicObject(): message(multilineText)
    let json = toJSON(obj)  # Automatic!
    
  2. Don’t parse invalid JSON without checking

    # ❌ Bad
    let obj = fromJSON(untrustedInput)  # May throw exception
    
    # βœ… Good
    try {
      let obj = fromJSON(untrustedInput)
    } catch (e) {
      # Handle error
    }
    
  3. Don’t manually build JSON with concatenation

    # ❌ Bad
    let json = "{\"name\":\"" + name + "\",\"age\":" + age + "}"
    
    # βœ… Good
    let obj = DynamicObject(): name(name): age(age)
    let json = toJSON(obj)
    

Summary

JSON support in GoloScript is:

For most use cases, prefer toJSON() for its safety and simplicity.

Β© 2026 GoloScript Project | Built with Gu10berg

Subscribe: πŸ“‘ RSS | βš›οΈ Atom