F# Guide — JSON: Parsing and Generating JSON Data
In this tutorial, you will learn about F# Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
F# JSON processing leverages type providers for compile-time types and libraries like System.Text.Json for runtime serialization, enabling type-safe JSON handling with minimal code.
What You'll Learn
- JSON type provider for type-safe access
- System.Text.Json serialization
- FSharp.Json library
- Manual JSON construction
- Performance considerations
Why It Matters
JSON is the universal data exchange format for APIs, configuration, and data storage. Durga Antivirus Pro uses JSON for API responses and configuration files.
Real-World Use
REST API clients, configuration files, data export/import, and web service communication.
flowchart LR
A["JSON"] --> B["Type Provider"]
B --> C["System.Text.Json"]
C --> D["Manual"]
D --> E["Performance"]
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
JSON Type Provider
open FSharp.Data
// Define from sample
type User = JsonProvider<"""
{"name":"Alice","email":"alice@example.com","age":30}
""">
// Parse JSON
let json = """{"name":"Bob","email":"bob@example.com","age":25}"""
let user = User.Parse(json)
user.Name // "Bob"
user.Email // "bob@example.com"
user.Age // 25
Arrays with Type Provider
open FSharp.Data
type Users = JsonProvider<"""
[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]
""">
let json = """[{"id":3,"name":"Carol"},{"id":4,"name":"Dave"}]"""
let users = Users.Parse(json)
for user in users do
printfn "%d: %s" user.Id user.Name
System.Text.Json
open System.Text.Json
open System.Text.Json.Serialization
// Define record for serialization
[<CLIMutable>]
type Person = {
Name: string
Email: string
Age: int
}
// Serialize
let person = { Name = "Alice"; Email = "a@example.com"; Age = 30 }
let json = JsonSerializer.Serialize(person)
// {"Name":"Alice","Email":"a@example.com","Age":30}
// Deserialize
let deserialized: Person = JsonSerializer.Deserialize(json)
Custom Serialization
open System.Text.Json
// Custom converter for discriminated unions
type Shape = Circle of float | Rectangle of float * float
let options = JsonSerializerOptions()
options.Converters.Add(FSharp.SystemTextJson.UnionConverter())
let json = JsonSerializer.Serialize(Circle 5.0, options)
let shape = JsonSerializer.Deserialize<Shape>(json, options)
Manual JSON Construction
open System.Text.Json
// Build JSON manually
let buildJson name email age =
use doc = JsonDocument.Parse(
sprintf """{"name":"%s","email":"%s","age":%d}""" name email age)
doc.RootElement
// Using JsonObject (System.Text.Json.Nodes)
open System.Text.Json.Nodes
let node = JsonObject()
node["name"] = "Alice"
node["age"] = 30
let json = node.ToJsonString()
Working with Nested JSON
type Address = {
Street: string
City: string
Zip: string
}
type Employee = {
Name: string
Address: Address
}
// Nested JSON
let json = """{"Name":"Alice","Address":{"Street":"123 Main","City":"Portland","Zip":"97201"}}"""
let employee = JsonSerializer.Deserialize<Employee>(json)
Performance
// System.Text.Json is the fastest option
// JsonProvider is convenient but slower
// For high throughput, use Utf8JsonReader/Writer
// Manual Utf8JsonReader for streaming
let readJsonStream (stream: System.IO.Stream) =
use reader = new System.Text.Json.Utf8JsonReader(
new System.Buffers.ArrayBufferWriter<byte>())
// Process tokens manually for maximum speed
Common Mistakes
1. Case sensitivity
JSON is case-sensitive. Ensure property names match between JSON and F# types.
2. Null handling
JSON null values map to F# options. Use string option or Option.ofObj for nullable fields.
3. Missing properties
Use JsonProvider with optional fields via JsonProvider<"...", SampleIsList=true> to handle missing fields.
4. Large JSON documents
Use streaming (Utf8JsonReader) for large documents instead of Parsing the entire string.
5. Type provider cache
Type providers cache schema. Clean and rebuild if the sample data changes.
Practice Questions
1. What are two ways to handle JSON in F#? JsonProvider for compile-time types and System.Text.Json for runtime serialization.
2. How do you handle optional JSON fields?
Use F# option types for nullable fields and JsonProvider with proper sample configuration.
3. Which JSON library is fastest? System.Text.Json is the fastest in the .NET ecosystem, being hardware-accelerated and allocation-efficient.
Challenge: Build a JSON configuration reader that deserializes a nested configuration structure.
FAQ
{{< faq question="Can JsonProvider handle dynamic JSON?" >}
JsonProvider requires a sample. For fully dynamic JSON, use JsonDocument.Parse directly.
{{< /faq >}}
{{< faq question="Is there a JSON computation expression?" >} Not built-in, but the FSharp.SystemTextJson library provides good interop with discriminated unions and records. {{< /faq >}}
{{< faq question="How do I handle camelCase JSON?" >}
Use JsonSerializerOptions(PropertyNamingPolicy = JsonNamingPolicy.CamelCase) with System.Text.Json.
{{< /faq >}}
{{< faq question="Can JSON be pretty-printed?" >}
Yes: JsonSerializer.Serialize(value, new JsonSerializerOptions(WriteIndented = true)).
{{< /faq >}}
{{< faq question="What is JsonDocument?" >} A lightweight read-only JSON parser that provides a DOM-like access pattern without deserializing to specific types. {{< /faq >}}
Mini Project
Build a JSON-based configuration system:
type Config = {
Host: string
Port: int
Features: string list
Database: {| Provider: string; ConnectionString: string |}
}
let loadConfig path =
let json = System.IO.File.ReadAllText(path)
JsonSerializer.Deserialize<Config>(json)
// config.json:
// {"Host":"localhost","Port":8080,"Features":["auth","logging"],"Database":{"Provider":"Postgres","ConnectionString":"host=localhost db=app"}}
let config = loadConfig "config.json"
printfn "Starting on %s:%d" config.Host config.Port
What's Next
Now that you understand JSON processing, explore HTTP clients for web API communication.
| Topic | Description | Link |
|---|---|---|
| F# HTTP | HTTP clients | {{< ref "25-http" >}} |
| F# Testing | Unit Testing | {{< ref "26-testing" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro