You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Thoth.Json解码"{}"并实现Status类型反序列化?

问题描述

对接一个提供get_status端点的API,规则如下:

  • 进程处于就绪状态时,返回JSON空对象{}
  • 未就绪时,返回包含原因的JSON对象

用F#联合类型建模状态:

type NotReady = { a: int; b: string } // 示例结构,实际根据API定义调整

type Status =
  | Ready
  | NotReady of NotReady

尝试过两种解码方案但都存在问题:

  1. 错误地将空对象{}当作字符串"{}"解码,导致Decode.fromString Decode.string "{}"报错:
    Error at: `$`
    Expecting a string but instead got: {}
    
  2. 使用可选字段解码的方案会将不符合预期的JSON(比如仅含部分字段的)错误地解码为Ready,无法准确校验数据合法性。

解决方案

核心思路是先判断JSON是否为空对象,再尝试解码NotReady结构,确保非法JSON会触发解码失败。

步骤1:实现NotReady类型的解码器

为NotReady定义强类型解码器,使用必填字段确保数据完整性:

module NotReady =
    let decoder =
        Decode.object (fun get ->
            { a = get.Required.Field "a" Decode.int
              b = get.Required.Field "b" Decode.string })

步骤2:实现Status联合类型的解码器

通过Decode.oneOf组合两个解码器,优先匹配空对象,再匹配NotReady结构:

module Status =
    let decoder: Decoder<Status> =
        // 解码空对象为Ready状态
        let emptyObjectDecoder =
            Decode.object (fun get ->
                if List.isEmpty get.Fields then
                    Decode.succeed Ready
                else
                    Decode.fail "Expected empty object for Ready status")
        
        // 解码NotReady状态
        let notReadyDecoder =
            NotReady.decoder |> Decode.map NotReady
        
        // 先尝试空对象解码,失败则尝试NotReady解码
        Decode.oneOf [ emptyObjectDecoder; notReadyDecoder ]

测试验证

let ready_json = "{}"
let not_ready_json = """{"a": 1, "b": "hello"}"""
let unexpected_json = """{"b":"not supported to happen"}"""

// 就绪状态解码
ready_json |> Decode.fromString Status.decoder 
// 输出:Ok Ready

// 未就绪状态解码
not_ready_json |> Decode.fromString Status.decoder
// 输出:Ok (NotReady { a = 1; b = "hello" })

// 非法JSON解码
unexpected_json |> Decode.fromString Status.decoder
// 输出:Error "Error at: `$.a`\nExpecting a field named 'a' but instead got object with fields: [\"b\"]"

说明

  • 空对象解码器通过检查get.Fields是否为空,确保只有严格的{}才会被解码为Ready
  • NotReady解码器使用Required.Field强制校验字段存在性,非法结构会直接解码失败,避免误判为Ready
  • 通过Decode.oneOf的顺序,优先匹配就绪状态的空对象,再处理未就绪的复杂结构

内容的提问来源于stack exchange,提问作者Chechy Levas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:07:16