Json
The Json utility allow you to parse any Json object via pattern matching.
You can either use classic function style or computation expression to parse your Json.
For next samples we will consider the following types:
type UserDef =
{ firstname : string
country : string }
type JsonDef =
{ size : int
users : UserDef list }
The json to parse is:
let jsonTxt =
"""
{
"size": 3,
"users": [
{
"firstname": "Maxime",
"country": "France"
},
{
"firstname": "Alfonso",
"country": "Spain"
},
{
"firstname": "Forki",
"country": "Germany"
}
]
}
"""
Using standard function
// Helpers function to unwrap a Json value
let unwrapNumber a =
match a with
| Json.Number a -> a
| _ -> failwith "Invalid JSON, it must be a number"
let unwrapString a =
match a with
| Json.String a -> a
| _ -> failwith "Invalid JSON, it must be a string"
let unwrapObject a =
match a with
| Json.Object a -> Map.ofArray a
| _ -> failwith "Invalid JSON, it must be an object"
let unwrapArray a =
match a with
| Json.Array a -> a
| _ -> failwith "Invalid JSON, it must be an array"
// Convert the Json string into Json DU
let json = jsonTxt |> Json.ofString |> unwrapResult |> unwrapObject
let sizeValue = json |> Map.find "size" |> unwrapNumber
let users = json |> Map.find "users" |> unwrapArray
let userList =
[ for user in users do
let obj = user |> unwrapObject
let firstname = obj |> Map.find "firstname" |> unwrapString
let country = obj |> Map.find "country" |> unwrapString
yield { firstname = firstname
country = country }
]
{ size = int sizeValue
users = userList } // Here we have our json extracted
Using computation expression
// Helpers to extract the Json values into a Result type
let number a =
match a with
| Json.Number a -> Ok(a)
| _ -> Error(System.Exception("Invalid JSON, it must be a number"))
let string a =
match a with
| Json.String a -> Ok(a)
| _ -> Error(System.Exception("Invalid JSON, it must be a string"))
let lookup (key: string) (a: Map<string, Json.Json>) =
match Map.tryFind key a with
| Some(a) -> Ok(a)
| None -> Error(System.Exception("Could not find key " + key))
let object a =
match a with
| Json.Object a -> Ok(Map.ofArray a)
| _ -> Error(System.Exception("Invalid JSON, it must be an object"))
let array a =
match a with
| Json.Array a -> Ok(a)
| _ -> Error(System.Exception("Invalid JSON, it must be an array"))
result {
let! json = jsonTxt |> Json.ofString |> Result.bind object
let! sizeValue = json |> lookup "size" |> Result.bind number
let! users = json |> lookup "users" |> Result.bind array
let userList =
seq {
for user in users ->
result {
let! obj = user |> object
let! firstname = obj |> lookup "firstname" |> Result.bind string
let! country = obj |> lookup "country" |> Result.bind string
return { firstname = firstname
country = country }
}
}
// Make sure all the users are valid
|> Seq.map unwrapResult
return { size = int sizeValue
users = List.ofSeq userList }
}
// We unwrap the result
// Make sure the parser succeeded
|> unwrapResult