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时,遇到记录更新歧义错误。
错误原因
- 类型不匹配:
Resource的name字段是Text类型,而ResourceCreateRequest的name是String,类型不兼容。 - 类型推断歧义:
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
相关产品推荐
相关产品推荐

