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

如何在OpenAPI/Haskell中展示完整的Schema定义?

如何生成包含所有依赖定义的完整JSON Schema(基于openapi3库)

我用openapi3库将Haskell的代数数据类型(ADT)转换为JSON Schema,相关代码如下:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE DeriveGeneric #-}     
{-# LANGUAGE TemplateHaskell #-}

module JSchema (Size)
    where

import Control.Lens
import Data.Proxy
import Data.OpenApi
import Types
import Deal
import GHC.Generics (Generic)
import Language.Haskell.TH
import Data.Aeson.TH
import Data.Aeson.Types

import Data.Ratio ((%))
import Data.Fixed

data Unit = Inch
          | Meter
          deriving (Show, Generic)

data Size = Balance Unit Int 
          | Balance2 Float
          | Size 
          deriving (Show, Generic)

instance ToSchema Size
$(deriveJSON defaultOptions ''Size)
instance ToSchema Unit
$(deriveJSON defaultOptions ''Unit)

当执行encodePretty $ toSchema $ (Proxy :: Proxy Size)生成Size的JSON Schema时,返回结果里只生成了指向Unit的$ref,没有包含Unit的具体定义。我需要给调用者提供完整的Schema,让他们能构造合法的JSON请求,但用toInlinedSchema会因为递归类型导致内存溢出,生成的Schema片段如下:

{
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "contents": {
          "items": [
            {
              "$ref": "#/components/schemas/Unit"   // 问题所在
            },
            {
              "maximum": 9223372036854775807,
              "type": "integer",
              "minimum": -9223372036854775808
            }
          ],
          "maxItems": 2,
          "type": "array",
          "minItems": 2
        },
        "tag": {
          "type": "string",
          "enum": [
            "Balance"
          ]
        }
      }
    }
    // 其他分支省略
  ]
}

请问怎么生成包含所有依赖定义的完整Schema?


解决方法

不要直接生成单个Schema,而是构建完整的OpenAPI文档对象,将所有需要的Schema(包括Size和Unit)添加到components/schemas中,这样生成的文档会包含所有引用的定义,同时避免递归内联的问题。

具体实现代码

修改代码,构建完整的OpenApi对象:

import Data.Aeson.Encode.Pretty (encodePretty)

main :: IO ()
main = do
  let sizeSchema = toSchema (Proxy :: Proxy Size)
      unitSchema = toSchema (Proxy :: Proxy Unit)
      -- 构建OpenAPI文档,添加schemas到components
      openApi = mempty
        & components . schemas . at "Size" ?~ sizeSchema
        & components . schemas . at "Unit" ?~ unitSchema
  -- 输出完整的OpenAPI文档
  print $ encodePretty openApi

说明

  • OpenApi对象是openapi3库的核心结构,包含了所有API相关的元数据,其中components/schemas用于存放可复用的Schema定义。
  • 通过lens库的操作符,将Size和Unit的Schema分别添加到schemas映射中,这样生成的JSON里,Size中的$ref就能正确指向#/components/schemas/Unit,同时Unit的定义也会出现在components/schemas下。
  • 这种方式既保留了引用的结构(避免递归溢出),又能提供完整的定义给调用者。

如果只需要Schema部分而不是完整的OpenAPI文档,可以从生成的OpenApi对象中提取components.schemas部分输出:

main :: IO ()
main = do
  let sizeSchema = toSchema (Proxy :: Proxy Size)
      unitSchema = toSchema (Proxy :: Proxy Unit)
      schemas = mempty
        & at "Size" ?~ sizeSchema
        & at "Unit" ?~ unitSchema
  print $ encodePretty schemas

内容的提问来源于stack exchange,提问作者Shawn Zhang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:02:28