Razumov
Razumov

Reputation: 324

Htmx POST to haskell servant handling optional field in FormUrlEncoded request

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.

Upvotes: 1

Views: 132

Answers (1)

Razumov
Razumov

Reputation: 324

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

Upvotes: 1

Related Questions