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

Htmx POST至Haskell Servant:处理表单可选字段解析异常

解决Servant中FromForm可选日期字段空值解析失败问题

问题分析

当表单提交空的endDate字段(如endDate=)时,parseMaybe会尝试将空字符串解析为Day类型,直接抛出解析错误并返回400响应。这是因为parseMaybe的逻辑是:字段不存在时返回Nothing,但字段存在且值无法解析为目标类型时,会返回错误而非Nothing。

服务端解决方案

自定义解析逻辑,先获取字段的原始文本值,判断是否为空,为空则返回Nothing;非空时再尝试解析为Day类型,同时保留无效格式的错误提示。

修改后的完整代码

import Data.Text (Text, isEmpty)
import Data.Time (Day)
import Data.Time.Format (parseTimeM, defaultTimeLocale)
import Servant (FromForm(..), Form, parseMaybe, parseUnique, parseAll)
import Data.Vector (Vector, fromList)

-- | Reading model.
data Reading = Reading
  { title :: String
  , authors :: Vector String
  , startDate :: Day
  , endDate :: Maybe Day
  }
  deriving (Eq, Show, Generic, ToJSON, FromJSON, FromRow)

-- 解析日期:空字符串返回Nothing,无效格式返回错误
parseDayAllowEmpty :: Text -> Either Text (Maybe Day)
parseDayAllowEmpty t
  | isEmpty t = Right Nothing
  | otherwise = case parseTimeM True defaultTimeLocale "%Y-%m-%d" t of
      Nothing -> Left $ "无效的日期格式: " <> t
      Just day -> Right $ Just day

-- 处理可选日期字段:兼容字段不存在、空值、有效/无效格式
parseOptionalDay :: Text -> Form -> Either Text (Maybe Day)
parseOptionalDay field f = do
  mTextVal <- parseMaybe field f
  case mTextVal of
    Nothing -> pure Nothing  -- 字段不存在
    Just val -> parseDayAllowEmpty val  -- 字段存在,判断空值并解析

-- | Allow form construction of a `Reading` instance.
instance FromForm Reading where
  fromForm :: Form -> Either Text Reading
  fromForm f =
    Reading
      <$> parseUnique "title" f
      <*> (fromList <$> parseAll "authors" f)
      <*> parseUnique "startDate" f
      <*> parseOptionalDay "endDate" f

方案效果

  • endDate字段省略时:返回Nothing
  • endDate提交空字符串时:返回Nothing
  • endDate提交有效日期(如2024-03-01)时:返回Just Day
  • endDate提交无效格式字符串(如abc)时:返回错误提示,保留参数校验逻辑

可选前端调整(非推荐)

在Htmx提交表单前,用JavaScript移除值为空的endDate字段,让服务端收到的请求不包含该字段,parseMaybe即可正常返回Nothing。但这种方式需要前端配合,不如服务端处理通用优雅。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 01:18:25