Micah Micah - 2 months ago 10
JSON Question

FSharp.Data -- How to Handle Null JSON Values?

I'm trying to convert the FSharp.Data examples to solutions for my problem i'm dealing with, but i'm just not getting very far.

Problem



Given an endpoint that returns json similar to:

{
Products:[{
Id:43,
Name:"hi"
},
{
Id:45,
Name:"other prod"
}
]
}


How can i load the data and then only get the
Id
s out of real, existing data?

I dont understand how to "pattern match out" the possibilities that:


  • it could return nothing

  • that
    root.Products
    could be not existing/empty

  • that
    Id
    might not exist



Attempt Via Null Matching



namespace Printio

open System
open FSharp.Data
open FSharp.Data.JsonExtensions

module PrintioApi =
type ApiProducts = JsonProvider<"https://api.print.io/api/v/1/source/widget/products?recipeId=f255af6f-9614-4fe2-aa8b-1b77b936d9d6&countryCode=US">

let getProductIds url =
async {
let! json = ApiProducts.AsyncLoad url
let ids = match json with
| null -> [||]
| _ ->
match json.Products with
| null -> [||]
| _ -> Array.map (fun (x:ApiProducts.Product)-> x.Id) json.Products

return ids
}

Answer

You probably don't need pattern matching for checking whether it's an empty array of not if you have some level of confidence in the source data. Something like this might just work fine: -

let getProductIds url =
    async {
        let! json = ApiProducts.AsyncLoad url
        return json.Products |> Seq.map(fun p -> p.Id) |> Seq.cache
    }

Note you shouldn't use Async.RunSynchronously when in an async { } block - you can do a let! binding which will await the result asynchronously.