From ce45c8e44094541af3a0857359785b8be607eafb Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Tue, 11 Jul 2023 14:24:25 +0300 Subject: [PATCH 1/8] Allow aeson-2.2 --- servant/servant.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servant/servant.cabal b/servant/servant.cabal index 331d4bc1c..947474ba7 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -100,7 +100,7 @@ library -- Here can be exceptions if we really need features from the newer versions. build-depends: base-compat >= 0.10.5 && < 0.14 - , aeson >= 1.4.1.0 && < 2.2 + , aeson >= 1.4.1.0 && < 2.3 , attoparsec >= 0.13.2.2 && < 0.15 , bifunctors >= 5.5.3 && < 5.7 , case-insensitive >= 1.2.0.11 && < 1.3 From 96aa9d9ce4c35c537074646eb1d27f2737795176 Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Tue, 11 Jul 2023 14:37:42 +0300 Subject: [PATCH 2/8] fail-fast: false for github actions https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#handling-failures --- .github/workflows/master.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 312fa7caf..e77edf2e0 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -20,6 +20,7 @@ jobs: - "9.2.8" - "9.4.5" - "9.6.2" + fail-fast: false steps: - uses: actions/checkout@v2 From 97dba0253efa650b3f299644c8608b74726afc6b Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Tue, 11 Jul 2023 20:14:03 +0300 Subject: [PATCH 3/8] Get rid of eitherDecodeLenient --- doc/tutorial/Server.lhs | 19 ++----------- servant/src/Servant/API/ContentTypes.hs | 30 ++------------------ servant/test/Servant/API/ContentTypesSpec.hs | 12 ++++---- 3 files changed, 9 insertions(+), 52 deletions(-) diff --git a/doc/tutorial/Server.lhs b/doc/tutorial/Server.lhs index 265bd707c..7e4103de7 100644 --- a/doc/tutorial/Server.lhs +++ b/doc/tutorial/Server.lhs @@ -47,7 +47,6 @@ import System.Directory import Text.Blaze import Text.Blaze.Html.Renderer.Utf8 import Servant.Types.SourceT (source) -import qualified Data.Aeson.Parser import qualified Text.Blaze.Html ``` @@ -431,25 +430,11 @@ class Accept ctype => MimeUnrender ctype a where mimeUnrender :: Proxy ctype -> ByteString -> Either String a ``` -We don't have much work to do there either, `Data.Aeson.eitherDecode` is -precisely what we need. However, it only allows arrays and objects as toplevel -JSON values and this has proven to get in our way more than help us so we wrote -our own little function around **aeson** and **attoparsec** that allows any type of -JSON value at the toplevel of a "JSON document". Here's the definition in case -you are curious. - -``` haskell -eitherDecodeLenient :: FromJSON a => ByteString -> Either String a -eitherDecodeLenient input = do - v :: Value <- parseOnly (Data.Aeson.Parser.value <* endOfInput) (cs input) - parseEither parseJSON v -``` - -This function is exactly what we need for our `MimeUnrender` instance. +As with `MimeRender`, we can use a function already available in `aeson`: `Data.Aeson.eitherDecode`. ``` haskell ignore instance FromJSON a => MimeUnrender JSON a where - mimeUnrender _ = eitherDecodeLenient + mimeUnrender _ = eitherDecode ``` And this is all the code that lets you use `JSON` with `ReqBody`, `Get`, diff --git a/servant/src/Servant/API/ContentTypes.hs b/servant/src/Servant/API/ContentTypes.hs index 8cfe2e1f5..390c8be25 100644 --- a/servant/src/Servant/API/ContentTypes.hs +++ b/servant/src/Servant/API/ContentTypes.hs @@ -65,7 +65,6 @@ module Servant.API.ContentTypes , AllMime(..) , AllMimeRender(..) , AllMimeUnrender(..) - , eitherDecodeLenient , canHandleAcceptH ) where @@ -75,13 +74,7 @@ import Control.Monad.Compat import Control.DeepSeq (NFData) import Data.Aeson - (FromJSON (..), ToJSON (..), encode) -import Data.Aeson.Parser - (value) -import Data.Aeson.Types - (parseEither) -import Data.Attoparsec.ByteString.Char8 - (endOfInput, parseOnly, skipSpace, ()) + (FromJSON (..), ToJSON (..), encode, eitherDecode) import Data.Bifunctor (bimap) import qualified Data.ByteString as BS @@ -371,28 +364,9 @@ instance NFData NoContent -------------------------------------------------------------------------- -- * MimeUnrender Instances --- | Like 'Data.Aeson.eitherDecode' but allows all JSON values instead of just --- objects and arrays. --- --- Will handle trailing whitespace, but not trailing junk. ie. --- --- >>> eitherDecodeLenient "1 " :: Either String Int --- Right 1 --- --- >>> eitherDecodeLenient "1 junk" :: Either String Int --- Left "trailing junk after valid JSON: endOfInput" -eitherDecodeLenient :: FromJSON a => ByteString -> Either String a -eitherDecodeLenient input = - parseOnly parser (cs input) >>= parseEither parseJSON - where - parser = skipSpace - *> Data.Aeson.Parser.value - <* skipSpace - <* (endOfInput "trailing junk after valid JSON") - -- | `eitherDecode` instance FromJSON a => MimeUnrender JSON a where - mimeUnrender _ = eitherDecodeLenient + mimeUnrender _ = eitherDecode -- | @urlDecodeAsForm@ -- Note that the @mimeUnrender p (mimeRender p x) == Right x@ law only diff --git a/servant/test/Servant/API/ContentTypesSpec.hs b/servant/test/Servant/API/ContentTypesSpec.hs index eb6d2a969..1ce6351a0 100644 --- a/servant/test/Servant/API/ContentTypesSpec.hs +++ b/servant/test/Servant/API/ContentTypesSpec.hs @@ -12,7 +12,7 @@ import Prelude () import Prelude.Compat import Data.Aeson - (FromJSON, ToJSON (..), Value, decode, encode, object, (.=)) + (FromJSON, ToJSON (..), Value, decode, encode, object, (.=), eitherDecode) import Data.ByteString.Char8 (ByteString, append, pack) import qualified Data.ByteString.Lazy as BSL @@ -219,15 +219,13 @@ spec = describe "Servant.API.ContentTypes" $ do handleCTypeH (Proxy :: Proxy '[JSONorText]) "image/jpeg" "foobar" `shouldBe` (Nothing :: Maybe (Either String Int)) - -- aeson >= 0.9 decodes top-level strings describe "eitherDecodeLenient" $ do + -- Since servant-0.20.1 MimeUnrender JSON instance uses eitherDecode, + -- as aeson >= 0.9 supports decoding top-level strings and numbers. it "parses top-level strings" $ do - let toMaybe = either (const Nothing) Just - -- The Left messages differ, so convert to Maybe - property $ \x -> toMaybe (eitherDecodeLenient x) - `shouldBe` (decode x :: Maybe String) - + property $ \x -> mimeUnrender (Proxy :: Proxy JSON) x + `shouldBe` (eitherDecode x :: Either String String) data SomeData = SomeData { record1 :: String, record2 :: Int } deriving (Generic, Eq, Show) From d074bba6f4f40dbe5994b5601bb4d01d42f9aa1f Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Wed, 12 Jul 2023 10:32:30 +0300 Subject: [PATCH 4/8] Run CI on push only to master --- .github/workflows/master.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index e77edf2e0..c4a68ca2b 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -3,6 +3,8 @@ name: CI on: pull_request: push: + branches: + - master jobs: cabal: From b9da2f3fff2fbc6ec7bfd975c7ee132d7b75cf5c Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Fri, 29 Sep 2023 17:27:43 +0300 Subject: [PATCH 5/8] Return eitherDecodeLenient as deprecated synonym --- servant/src/Servant/API/ContentTypes.hs | 7 +++++++ servant/test/Servant/API/ContentTypesSpec.hs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/servant/src/Servant/API/ContentTypes.hs b/servant/src/Servant/API/ContentTypes.hs index 390c8be25..24dc50779 100644 --- a/servant/src/Servant/API/ContentTypes.hs +++ b/servant/src/Servant/API/ContentTypes.hs @@ -65,6 +65,7 @@ module Servant.API.ContentTypes , AllMime(..) , AllMimeRender(..) , AllMimeUnrender(..) + , eitherDecodeLenient , canHandleAcceptH ) where @@ -364,6 +365,12 @@ instance NFData NoContent -------------------------------------------------------------------------- -- * MimeUnrender Instances +-- | Deprecated: since aeson version 0.9 `eitherDecode` has lenient behavior. +-- +eitherDecodeLenient :: FromJSON a => ByteString -> Either String a +eitherDecodeLenient = eitherDecode +{-# DEPRECATED eitherDecodeLenient "use eitherDecode instead" #-} + -- | `eitherDecode` instance FromJSON a => MimeUnrender JSON a where mimeUnrender _ = eitherDecode diff --git a/servant/test/Servant/API/ContentTypesSpec.hs b/servant/test/Servant/API/ContentTypesSpec.hs index 1ce6351a0..8de7a1d87 100644 --- a/servant/test/Servant/API/ContentTypesSpec.hs +++ b/servant/test/Servant/API/ContentTypesSpec.hs @@ -219,7 +219,7 @@ spec = describe "Servant.API.ContentTypes" $ do handleCTypeH (Proxy :: Proxy '[JSONorText]) "image/jpeg" "foobar" `shouldBe` (Nothing :: Maybe (Either String Int)) - describe "eitherDecodeLenient" $ do + describe "eitherDecode is lenient" $ do -- Since servant-0.20.1 MimeUnrender JSON instance uses eitherDecode, -- as aeson >= 0.9 supports decoding top-level strings and numbers. From 3ce5741f48bbcd678b1a7e6dda49ef324517c23a Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Fri, 29 Sep 2023 17:28:07 +0300 Subject: [PATCH 6/8] servant 0.20.1 --- servant/CHANGELOG.md | 5 +++++ servant/servant.cabal | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/servant/CHANGELOG.md b/servant/CHANGELOG.md index 468d7884e..2846e4417 100644 --- a/servant/CHANGELOG.md +++ b/servant/CHANGELOG.md @@ -2,6 +2,11 @@ Package versions follow the [Package Versioning Policy](https://pvp.haskell.org/): in A.B.C, bumps to either A or B represent major versions. +0.20.1 +---- + +- Support aeson-2.2 [#1695](https://github.com/haskell-servant/servant/pull/1695) + 0.20 ---- diff --git a/servant/servant.cabal b/servant/servant.cabal index 947474ba7..bc681308e 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -1,6 +1,6 @@ cabal-version: 2.2 name: servant -version: 0.20 +version: 0.20.1 synopsis: A family of combinators for defining webservices APIs category: Servant, Web From 57e0f29719cbd0ce34fa10d2e4e256e304b63965 Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Sun, 1 Oct 2023 14:23:51 +0300 Subject: [PATCH 7/8] Drop constraint on warp in cabal.project Relevant issue seems to be fixed upstream. --- cabal.project | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cabal.project b/cabal.project index 5663f806e..92e697016 100644 --- a/cabal.project +++ b/cabal.project @@ -53,10 +53,9 @@ tests: True optimization: False -- reorder-goals: True --- The switch to crypton breaks the build, so let's avoid it for now --- https://github.com/snoyberg/http-client/issues/508 -constraints: crypton < 0, crypton-connection < 0, crypton-x509 < 0, crypton-x509-store < 0, crypton-x509-system < 0, crypton-x509-validation < 0 -constraints: warp < 3.3.26 +-- wreq-0.5.4.1 doesn't seem to work with ghc-8.6.5 +if (impl(ghc < 8.8)) + constraints: wreq == 0.5.4.0 allow-newer: servant-js:base From 8a4a7f59abd9a07f29e282026a8f18c1e7bd8b71 Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Sun, 1 Oct 2023 14:46:44 +0300 Subject: [PATCH 8/8] Constraint http2 <4.2 --- cabal.project | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cabal.project b/cabal.project index 92e697016..2239b77c9 100644 --- a/cabal.project +++ b/cabal.project @@ -53,6 +53,12 @@ tests: True optimization: False -- reorder-goals: True +-- Older warp versions fail to build with https >= 4.2: +-- Network/Wai/Handler/Warp/HTTP2.hs:48:16: error: +-- Error: • Constructor ‘H2.Config’ does not have the required strict field(s): confMySockAddr, +-- confPeerSockAddr +constraints: http2 <4.2 + -- wreq-0.5.4.1 doesn't seem to work with ghc-8.6.5 if (impl(ghc < 8.8)) constraints: wreq == 0.5.4.0