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

IHP中JSON载荷转Record类型遇类型歧义问题求助

解决IHP中JSON转自动生成Record类型的歧义问题

问题背景

你使用IHP自动生成了Resource类型:

data Resource' userId providerId bookings = Resource 
  { id :: (Id' "resources")
  , createdAt :: UTCTime
  , updatedAt :: UTCTime
  , userId :: userId
  , providerId :: providerId
  , name :: Text
  , bookings :: bookings
  , meta :: MetaBag
  } deriving (Eq, Show)
type Resource = Resource' (Id' "users") (Id' "providers")(QueryBuilder.QueryBuilder "bookings")

为了解析JSON载荷,你创建了临时记录ResourceCreateRequest:

data ResourceCreateRequest = ResourceCreateRequest { name :: String }

instance FromJSON ResourceCreateRequest where
  parseJSON = withObject "Resource" $ \o -> ResourceCreateRequest <$> o .: "name"

JSON载荷为:

{"name": "X"}

尝试用临时记录更新newRecord @Resource时,遇到记录更新歧义错误。

错误原因

  1. 类型不匹配:Resource的name字段是Text类型,而ResourceCreateRequest的name是String,类型不兼容。
  2. 类型推断歧义:newRecord @Resource返回的是NewRecord Resource类型(IHP用于创建新记录的包装类型),直接用记录更新语法时,编译器无法明确推断最终类型。

解决方案

方法一:使用IHP官方推荐的setField函数(优先选择)

IHP提供setField函数安全更新记录字段,避免类型歧义,同时简化代码:

-- 导入必要模块
import IHP.ModelSupport (setField)
import Data.Text (Text, pack)

-- 优化临时记录类型(可选,避免重复类型转换)
data ResourceCreateRequest = ResourceCreateRequest { name :: Text }

instance FromJSON ResourceCreateRequest where
  parseJSON = withObject "Resource" $ \o -> ResourceCreateRequest <$> o .: "name"

-- 控制器代码
"application/json" -> do
    -- 正确解析请求体到临时记录
    resourceCreateRequest <- parseBody @ResourceCreateRequest
    -- 使用setField更新字段
    let newResource = setField #name (JRCR.name resourceCreateRequest) (newRecord @Resource)
    renderJson newResource

方法二:明确标注类型消除歧义

如果坚持使用记录更新语法,需要给更新后的记录明确标注类型:

import Data.Text (pack)

-- 控制器代码
"application/json" -> do
    resourceCreateRequest <- parseBody @ResourceCreateRequest
    -- 明确标注类型为NewRecord Resource
    let newResource = (newRecord @Resource :: NewRecord Resource){ name = pack $ JRCR.name resourceCreateRequest }
    renderJson newResource

关键注意点

  • 必须用parseBody @ResourceCreateRequest解析请求体,而不是直接从getRequest取字段(getRequest返回的是请求对象,不是解析后的记录)。
  • 确保字段类型一致:要么把临时记录的name改成Text,要么用pack把String转成Text。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 02:50:22