Skip to content

Commit 783cff5

Browse files
committed
Change fromMultipart result to Either String a
This allows users of the library to provide more fine-grained error messages for their FromMultipart instances.
1 parent a7d888e commit 783cff5

File tree

2 files changed

+17
-9
lines changed

2 files changed

+17
-9
lines changed

servant-multipart.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ library
4444
, servant-docs >=0.10 && <0.15
4545
, servant-foreign >=0.15 && <0.16
4646
, servant-server >=0.16 && <0.18
47+
, string-conversions >=0.4.0.1 && <0.5
4748
, wai >=3.2.1.2 && <3.3
4849
, wai-extra >=3.0.24.3 && <3.1
4950

src/Servant/Multipart.hs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import Data.Foldable (foldMap, foldl')
4949
import Data.List (find)
5050
import Data.Maybe
5151
import Data.Monoid
52+
import Data.String.Conversions (cs)
5253
import Data.Text (Text, unpack)
5354
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
5455
import Data.Typeable
@@ -209,8 +210,11 @@ deriving instance Eq (MultipartResult tag) => Eq (FileData tag)
209210
deriving instance Show (MultipartResult tag) => Show (FileData tag)
210211

211212
-- | Lookup a file input with the given @name@ attribute.
212-
lookupFile :: Text -> MultipartData tag -> Maybe (FileData tag)
213-
lookupFile iname = find ((==iname) . fdInputName) . files
213+
lookupFile :: Text -> MultipartData tag -> Either String (FileData tag)
214+
lookupFile iname =
215+
maybe (Left $ "File " <> cs iname <> " not found") Right
216+
. find ((==iname) . fdInputName)
217+
. files
214218

215219
-- | Representation for a textual input (any @\<input\>@ type but @file@).
216220
--
@@ -221,8 +225,11 @@ data Input = Input
221225
} deriving (Eq, Show)
222226

223227
-- | Lookup a textual input with the given @name@ attribute.
224-
lookupInput :: Text -> MultipartData tag -> Maybe Text
225-
lookupInput iname = fmap iValue . find ((==iname) . iName) . inputs
228+
lookupInput :: Text -> MultipartData tag -> Either String Text
229+
lookupInput iname =
230+
maybe (Left $ "Field " <> cs iname <> " not found") (Right . iValue)
231+
. find ((==iname) . iName)
232+
. inputs
226233

227234
-- | 'MultipartData' is the type representing
228235
-- @multipart/form-data@ form inputs. Sometimes
@@ -246,10 +253,10 @@ class FromMultipart tag a where
246253
-- in a list of textual inputs and another list for
247254
-- files, try to extract a value of type @a@. When
248255
-- extraction fails, servant errors out with status code 400.
249-
fromMultipart :: MultipartData tag -> Maybe a
256+
fromMultipart :: MultipartData tag -> Either String a
250257

251258
instance FromMultipart tag (MultipartData tag) where
252-
fromMultipart = Just
259+
fromMultipart = Right
253260

254261
-- | Allows you to tell servant how to turn a more structured type
255262
-- into a 'MultipartData', which is what is actually sent by the
@@ -434,9 +441,9 @@ addMultipartHandling pTag opts subserver =
434441
bodyCheck () = do
435442
mpd <- check pTag opts :: DelayedIO (MultipartData tag)
436443
case fromMultipart mpd of
437-
Nothing -> liftRouteResult $ FailFatal
438-
err400 { errBody = "fromMultipart returned Nothing" }
439-
Just x -> return x
444+
Left msg -> liftRouteResult $ FailFatal
445+
err400 { errBody = "Could not decode multipart mime body: " <> cs msg }
446+
Right x -> return x
440447

441448
contentTypeH req = fromMaybe "application/octet-stream" $
442449
lookup "Content-Type" (requestHeaders req)

0 commit comments

Comments
 (0)