JSON Type Generator
Generate F# types from JSON samples using the Json widget provided by Fabulous.AST.Json.
This extension parses JSON strings and emits record and alias declarations that describe the shape of the data.
Installation
|
💡 Tip: For automatic build-time generation, see the Build Extension tutorial.
#r "../../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.Core.dll"
#r "../../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
#r "../../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fabulous.AST.dll"
#r "../../extensions/Fabulous.AST.Json/bin/Release/net8.0//Fabulous.AST.Json.dll"
open Fabulous.AST
open Fabulous.AST.Json
open type Fabulous.AST.Ast
Step 1: Basic Type Generation
The simplest use case - generate a record from a JSON object:
Oak() {
AnonymousModule() {
let json =
"""
{
"name": "Alice",
"age": 30,
"active": true
}
"""
Json(json)
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Step 2: Custom Root Type Name
Override the default Root name with .rootName():
Oak() {
AnonymousModule() {
let json = """{ "id": 1, "email": "alice@example.com" }"""
Json(json).rootName("User")
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Step 3: Nested Objects
Nested JSON objects become nested record types:
Oak() {
AnonymousModule() {
let json =
"""
{
"user": {
"name": "Alice",
"address": {
"city": "London",
"country": "UK"
}
}
}
"""
Json(json).rootName("Response")
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Step 4: Arrays
Arrays generate an element type and a list alias:
Oak() {
AnonymousModule() {
let json =
"""
[
{ "id": 1, "name": "Item 1" },
{ "id": 2, "name": "Item 2" }
]
"""
Json(json).rootName("Products")
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Step 5: Optional Fields
Fields missing or null in some array elements become option types:
Oak() {
AnonymousModule() {
let json =
"""
[
{ "id": 1, "name": "Alice", "nickname": "Ali" },
{ "id": 2, "name": "Bob" }
]
"""
Json(json).rootName("Users")
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Step 6: Relaxed JSON Parsing
Handle JSON with comments and trailing commas:
let jsonWithComments =
"""
{
// a comment
"id": 1,
"name": "Test",
}
"""
Oak() {
AnonymousModule() {
Json(jsonWithComments)
.documentAllowTrailingCommas(true)
.documentCommentHandling(System.Text.Json.JsonCommentHandling.Skip)
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Step 7: Case-Insensitive Property Names
Merge properties with inconsistent casing:
Oak() {
AnonymousModule() {
let json =
"""
[
{ "ID": 1, "Name": "First" },
{ "id": 2, "name": "Second" }
]
"""
Json(json).nodePropertyNameCaseInsensitive(true)
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Step 8: Namespaces and Modules
Wrap generated types in a namespace:
Oak() {
Namespace("MyApp.Models") {
let json = """{ "id": 1, "name": "Alice" }"""
Json(json).rootName("User")
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Or in a module:
Oak() {
Module("MyApp.Models") {
let json = """{ "id": 1, "name": "Alice" }"""
Json(json).rootName("User")
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Type Inference Rules
JSON Value |
F# Type |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record type |
Special Field Name Handling
Leading Digits
Fields starting with digits are prefixed with _:
Oak() {
AnonymousModule() {
let json = """{ "2faEnabled": true, "3rdPartyId": "abc" }"""
Json(json)
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
Reserved Keywords
F# keywords are escaped with double backticks:
Oak() {
AnonymousModule() {
let json = """{ "type": "admin", "class": "premium" }"""
Json(json)
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces:
|
API Reference
Modifier |
Description |
|---|---|
|
Set root type name (default: |
|
Provide parsing options |
|
Allow trailing commas |
|
Handle JSON comments |
|
Maximum nesting depth |
|
Seed options from serializer config |
|
Case-insensitive property matching |
Next Steps
- Learn about automatic build-time generation with Fabulous.AST.Build
- Explore the Fabulous.AST DSL for more code generation options
static member Ast.Oak: unit -> CollectionBuilder<Fantomas.Core.SyntaxOak.Oak,'marker>
--------------------
module Oak from Fabulous.AST
static member Ast.Json: json: string -> WidgetBuilder<Fantomas.Core.SyntaxOak.ModuleOrNamespaceNode>
--------------------
module Json from Fabulous.AST.Json
--------------------
namespace Fabulous.AST.Json
<summary> It takes the root of the widget tree and create the corresponding Fantomas node, and recursively creating all children nodes </summary>
<summary>Defines how the <see cref="T:System.Text.Json.Utf8JsonReader" /> struct handles comments.</summary>
Fabulous.AST