Skip to content

Commit 97dba02

Browse files
committed
Get rid of eitherDecodeLenient
1 parent 96aa9d9 commit 97dba02

File tree

3 files changed

+9
-52
lines changed

3 files changed

+9
-52
lines changed

doc/tutorial/Server.lhs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ import System.Directory
4747
import Text.Blaze
4848
import Text.Blaze.Html.Renderer.Utf8
4949
import Servant.Types.SourceT (source)
50-
import qualified Data.Aeson.Parser
5150
import qualified Text.Blaze.Html
5251
```
5352
@@ -431,25 +430,11 @@ class Accept ctype => MimeUnrender ctype a where
431430
mimeUnrender :: Proxy ctype -> ByteString -> Either String a
432431
```
433432
434-
We don't have much work to do there either, `Data.Aeson.eitherDecode` is
435-
precisely what we need. However, it only allows arrays and objects as toplevel
436-
JSON values and this has proven to get in our way more than help us so we wrote
437-
our own little function around **aeson** and **attoparsec** that allows any type of
438-
JSON value at the toplevel of a "JSON document". Here's the definition in case
439-
you are curious.
440-
441-
``` haskell
442-
eitherDecodeLenient :: FromJSON a => ByteString -> Either String a
443-
eitherDecodeLenient input = do
444-
v :: Value <- parseOnly (Data.Aeson.Parser.value <* endOfInput) (cs input)
445-
parseEither parseJSON v
446-
```
447-
448-
This function is exactly what we need for our `MimeUnrender` instance.
433+
As with `MimeRender`, we can use a function already available in `aeson`: `Data.Aeson.eitherDecode`.
449434
450435
``` haskell ignore
451436
instance FromJSON a => MimeUnrender JSON a where
452-
mimeUnrender _ = eitherDecodeLenient
437+
mimeUnrender _ = eitherDecode
453438
```
454439
455440
And this is all the code that lets you use `JSON` with `ReqBody`, `Get`,

servant/src/Servant/API/ContentTypes.hs

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ module Servant.API.ContentTypes
6565
, AllMime(..)
6666
, AllMimeRender(..)
6767
, AllMimeUnrender(..)
68-
, eitherDecodeLenient
6968
, canHandleAcceptH
7069
) where
7170

@@ -75,13 +74,7 @@ import Control.Monad.Compat
7574
import Control.DeepSeq
7675
(NFData)
7776
import Data.Aeson
78-
(FromJSON (..), ToJSON (..), encode)
79-
import Data.Aeson.Parser
80-
(value)
81-
import Data.Aeson.Types
82-
(parseEither)
83-
import Data.Attoparsec.ByteString.Char8
84-
(endOfInput, parseOnly, skipSpace, (<?>))
77+
(FromJSON (..), ToJSON (..), encode, eitherDecode)
8578
import Data.Bifunctor
8679
(bimap)
8780
import qualified Data.ByteString as BS
@@ -371,28 +364,9 @@ instance NFData NoContent
371364
--------------------------------------------------------------------------
372365
-- * MimeUnrender Instances
373366

374-
-- | Like 'Data.Aeson.eitherDecode' but allows all JSON values instead of just
375-
-- objects and arrays.
376-
--
377-
-- Will handle trailing whitespace, but not trailing junk. ie.
378-
--
379-
-- >>> eitherDecodeLenient "1 " :: Either String Int
380-
-- Right 1
381-
--
382-
-- >>> eitherDecodeLenient "1 junk" :: Either String Int
383-
-- Left "trailing junk after valid JSON: endOfInput"
384-
eitherDecodeLenient :: FromJSON a => ByteString -> Either String a
385-
eitherDecodeLenient input =
386-
parseOnly parser (cs input) >>= parseEither parseJSON
387-
where
388-
parser = skipSpace
389-
*> Data.Aeson.Parser.value
390-
<* skipSpace
391-
<* (endOfInput <?> "trailing junk after valid JSON")
392-
393367
-- | `eitherDecode`
394368
instance FromJSON a => MimeUnrender JSON a where
395-
mimeUnrender _ = eitherDecodeLenient
369+
mimeUnrender _ = eitherDecode
396370

397371
-- | @urlDecodeAsForm@
398372
-- Note that the @mimeUnrender p (mimeRender p x) == Right x@ law only

servant/test/Servant/API/ContentTypesSpec.hs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Prelude ()
1212
import Prelude.Compat
1313

1414
import Data.Aeson
15-
(FromJSON, ToJSON (..), Value, decode, encode, object, (.=))
15+
(FromJSON, ToJSON (..), Value, decode, encode, object, (.=), eitherDecode)
1616
import Data.ByteString.Char8
1717
(ByteString, append, pack)
1818
import qualified Data.ByteString.Lazy as BSL
@@ -219,15 +219,13 @@ spec = describe "Servant.API.ContentTypes" $ do
219219
handleCTypeH (Proxy :: Proxy '[JSONorText]) "image/jpeg"
220220
"foobar" `shouldBe` (Nothing :: Maybe (Either String Int))
221221

222-
-- aeson >= 0.9 decodes top-level strings
223222
describe "eitherDecodeLenient" $ do
224223

224+
-- Since servant-0.20.1 MimeUnrender JSON instance uses eitherDecode,
225+
-- as aeson >= 0.9 supports decoding top-level strings and numbers.
225226
it "parses top-level strings" $ do
226-
let toMaybe = either (const Nothing) Just
227-
-- The Left messages differ, so convert to Maybe
228-
property $ \x -> toMaybe (eitherDecodeLenient x)
229-
`shouldBe` (decode x :: Maybe String)
230-
227+
property $ \x -> mimeUnrender (Proxy :: Proxy JSON) x
228+
`shouldBe` (eitherDecode x :: Either String String)
231229

232230
data SomeData = SomeData { record1 :: String, record2 :: Int }
233231
deriving (Generic, Eq, Show)

0 commit comments

Comments
 (0)