我正在尝试将FSharp.Data示例转换为我正在处理的问题的解决方案,但我只是没有走得太远.
给定返回json的端点类似于:
{
Products:[{
Id:43,
Name:"hi"
},
{
Id:45,
Name:"other prod"
}
]
}
Run Code Online (Sandbox Code Playgroud)
如何加载数据然后只Id从实际的现有数据中获取数据?
我不明白如何"模式匹配"的可能性:
root.Products可能是不存在/空Id可能不存在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
}
Run Code Online (Sandbox Code Playgroud)
编辑:当我写这个答案时,我没有完全理解 JSON 类型提供程序的功能。事实证明,您可以使用示例 JSON 文档列表填充它,这使您能够处理可能存在或不存在数据的各种场景。这些天我经常使用它,所以我不再相信我最初写的东西。我会在这里留下原始答案,以防任何人都可以从中获得任何价值。
虽然类型提供程序很好,但我认为尝试将像 JSON 这样没有模式和类型安全的东西当作强类型数据在概念上是错误的。我没有使用类型提供程序,而是使用HttpClient、Json.NET和FSharp.Interop.Dynamic来编写这样的查询:
let response = client.GetAsync("").Result
let json = response.Content.ReadAsJsonAsync().Result
let links = json?links :> obj seq
let address =
links
|> Seq.filter (fun l -> l?rel <> null && l?href <> null)
|> Seq.filter (fun l -> l?rel.ToString() = rel)
|> Seq.map (fun l -> Uri(l?href.ToString()))
|> Seq.exactlyOne
Run Code Online (Sandbox Code Playgroud)
whereclient是 的一个实例HttpClient,ReadAsJsonAsync是一个像这样定义的小助手方法:
type HttpContent with
member this.ReadAsJsonAsync() =
let readJson (t : Task<string>) =
JsonConvert.DeserializeObject t.Result
this.ReadAsStringAsync().ContinueWith(fun t -> readJson t)
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
Note you shouldn't use Async.RunSynchronously when in an async { } block - you can do a let! binding which will await the result asynchronously.
| 归档时间: |
|
| 查看次数: |
1092 次 |
| 最近记录: |