I am using Htmx to POST a form to a Haskell Servant endpoint. The endpoint has a model with a FromForm
instance. There is an optional field in the form. If the field is excluded in the POST, the client will receive a 400 with response "Unexpected end-of-input, expecting -, +, or a digit", indicating the parsing failed.
-- | Reading model.
data Reading = Reading
{ title :: String
, authors :: Vector String
, startDate :: Day
, endDate :: Maybe Day
}
deriving (Eq, Show, Generic, ToJSON, FromJSON, FromRow)
-- | 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
<*> parseMaybe "endDate" f
The actual FormUrlEncoded bytestring that gets POSTed is title=asdf&authors=asdf&startDate=2024-03-01&endDate=
. How can I work around this? I suspect there is a way to make servant handle this elegantly, but I am also considering client side changes (althought that seems less ideal).
I have seen this post but felt there must be an alternative to wrapping the Maybe
. Also, maybe there is something I can do through Htmx for my specific use case.
I landed on a generic parser function with the signature suggested by @Ismor.
It works as expected, I imagine I will always use this in place of parseMaybe
when handling incoming form data.
parseOptionalMaybe :: FromHttpApiData v => Text -> Form -> Either Text (Maybe v)
parseOptionalMaybe fieldName form = do
maybeField <- lookupMaybe fieldName form
case maybeField of
Just "" -> return Nothing
Just _ -> parseMaybe fieldName form
Nothing -> return Nothing