packages feed

servant-swagger 1.1.5 → 1.1.6

raw patch · 15 files changed

+245/−127 lines, 15 filesdep +aeson-prettydep +base-compatdep +template-haskelldep −aeson-qqdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: aeson-pretty, base-compat, template-haskell, utf8-string

Dependencies removed: aeson-qq

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Servant.Swagger.Internal.Test: maybeCounterExample :: Maybe String -> Property
+ Servant.Swagger.Internal.Test: prettyValidateWith :: forall a. (ToJSON a, ToSchema a) => (a -> [ValidationError]) -> a -> Maybe String
- Servant.Swagger.Internal.Test: props :: forall p p'' cs xs. TMap (Every (Typeable : (Show : (Arbitrary : cs)))) xs => p cs -> (forall x. EveryTF cs x => x -> Bool) -> p'' xs -> Spec
+ Servant.Swagger.Internal.Test: props :: forall p p'' cs xs. TMap (Every (Typeable : Show : Arbitrary : cs)) xs => p cs -> (forall x. EveryTF cs x => x -> Property) -> p'' xs -> Spec

Files

CHANGELOG.md view
@@ -1,3 +1,12 @@+1.1.6+-----++* Fixes:+  * `validateEveryToJSON` now prints validation errors++* Notes:+  * GHC-8.6 compatible release+ 1.1.5 ----- 
README.md view
@@ -11,7 +11,7 @@  ### Motivation -Swagger™ is a project used to describe and document RESTful APIs.+Swagger is a project used to describe and document RESTful APIs. Unlike Servant it is language-agnostic and thus is quite popular among developers in different languages. It also exists for a longer time and has more tools to work with. 
example/swagger.json view
@@ -56,7 +56,7 @@                     }                 },                 "produces": [-                    "application/json"+                    "application/json;charset=utf-8"                 ],                 "parameters": [                     {@@ -71,7 +71,7 @@             },             "put": {                 "consumes": [-                    "application/json"+                    "application/json;charset=utf-8"                 ],                 "responses": {                     "404": {@@ -88,7 +88,7 @@                     }                 },                 "produces": [-                    "application/json"+                    "application/json;charset=utf-8"                 ],                 "parameters": [                     {@@ -113,7 +113,7 @@         "/todo": {             "post": {                 "consumes": [-                    "application/json"+                    "application/json;charset=utf-8"                 ],                 "responses": {                     "400": {@@ -127,7 +127,7 @@                     }                 },                 "produces": [-                    "application/json"+                    "application/json;charset=utf-8"                 ],                 "parameters": [                     {@@ -153,7 +153,7 @@                     }                 },                 "produces": [-                    "application/json"+                    "application/json;charset=utf-8"                 ]             }         }
servant-swagger.cabal view
@@ -1,8 +1,8 @@ name:                servant-swagger-version:             1.1.5+version:             1.1.6 synopsis:            Generate Swagger specification for your servant API. description:-  Swagger™ is a project used to describe and document RESTful APIs.+  Swagger is a project used to describe and document RESTful APIs.   Unlike Servant it is language-agnostic and thus is quite popular among developers   in different languages. It also exists for a longer time and has more tools to work with.   .@@ -27,10 +27,12 @@ build-type:          Custom cabal-version:       1.18 tested-with:-  GHC==7.8.4,-  GHC==7.10.3,-  GHC==8.0.2,-  GHC==8.2.2+  GHC ==7.8.4+   || ==7.10.3+   || ==8.0.2+   || ==8.2.2+   || ==8.4.4+   || ==8.6.1  extra-source-files:     README.md@@ -51,8 +53,8 @@  custom-setup   setup-depends:-    base >=4.7 && <4.11,-    Cabal >= 1.18 && <2.1,+    base >=4.7 && <4.13,+    Cabal >= 1.18 && <2.5,     cabal-doctest >=1.0.2 && <1.1  library@@ -70,15 +72,16 @@     Servant.Swagger.Internal.TypeLevel.Every     Servant.Swagger.Internal.TypeLevel.TMap   hs-source-dirs:      src-  build-depends:       aeson                     >=0.11.2.0 && <1.3-                     , base                      >=4.7.0.0  && <4.11+  build-depends:       aeson                     >=0.11.2.0 && <1.5+                     , aeson-pretty              >=0.4      && <0.9+                     , base                      >=4.7.0.0  && <4.13                      , bytestring                >=0.10.4.0 && <0.11                      , http-media                >=0.6.3    && <0.8                      , insert-ordered-containers >=0.1.0.0  && <0.3-                     , lens                      >=4.7.0.1  && <4.17-                     , servant                   >=0.13     && <0.14+                     , lens                      >=4.7.0.1  && <4.18+                     , servant                   >=0.13     && <0.15                      , singleton-bool            >=0.1.3    && <0.2-                     , swagger2                  >=2.1      && <2.3+                     , swagger2                  >=2.1      && <2.4                      , text                      >=1.2.0.6  && <1.3                      , unordered-containers      >=0.2.5.1  && <0.3 @@ -91,7 +94,7 @@   build-depends:     base,     directory >= 1.0,-    doctest >= 0.11.1 && <0.14,+    doctest >= 0.11.1 && <0.17,     servant,     QuickCheck,     filepath@@ -107,8 +110,8 @@   main-is:          Spec.hs   build-tool-depends: hspec-discover:hspec-discover   build-depends:    base+                  , base-compat >= 0.10.4 && <0.11                   , aeson-                  , aeson-qq >=0.8.1                   , hspec                   , QuickCheck                   , lens@@ -116,7 +119,10 @@                   , servant-swagger                   , swagger2                   , text+                  , template-haskell+                  , utf8-string >=1.0.1.1 && <1.1                   , time   other-modules:     Servant.SwaggerSpec+    Data.Aeson.QQ.Simple2   default-language: Haskell2010
src/Servant/Swagger.hs view
@@ -7,14 +7,14 @@ -- This module provides means to generate and manipulate -- Swagger specification for servant APIs. ----- Swagger™ is a project used to describe and document RESTful APIs.+-- Swagger is a project used to describe and document RESTful APIs. -- -- The Swagger specification defines a set of files required to describe such an API. -- These files can then be used by the Swagger-UI project to display the API -- and Swagger-Codegen to generate clients in various languages. -- Additional utilities can also take advantage of the resulting files, such as testing tools. ----- For more information see <http://swagger.io/ Swagger™ documentation>.+-- For more information see <http://swagger.io/ Swagger documentation>. module Servant.Swagger (   -- * How to use this library   -- $howto@@ -158,9 +158,11 @@ -- >>> hspec $ validateEveryToJSON (Proxy :: Proxy UserAPI) -- <BLANKLINE> -- [User]+-- ... -- User+-- ... -- UserId--- <BLANKLINE>+-- ... -- Finished in ... seconds -- 3 examples, 0 failures --
src/Servant/Swagger/Internal.hs view
@@ -1,40 +1,44 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE CPP                  #-}+{-# LANGUAGE ConstraintKinds      #-}+{-# LANGUAGE DataKinds            #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE PolyKinds            #-}+{-# LANGUAGE RankNTypes           #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE TypeOperators        #-} #if __GLASGOW_HASKELL__ >= 710 #define OVERLAPPABLE_ {-# OVERLAPPABLE #-} #else {-# LANGUAGE OverlappingInstances #-} #define OVERLAPPABLE_ #endif+#if __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE UndecidableInstances #-}+#endif module Servant.Swagger.Internal where -import Control.Lens-import Data.Aeson-import Data.Monoid-import Data.Proxy-import qualified Data.Swagger as Swagger-import Data.Swagger hiding (Header)-import Data.Swagger.Declare-import Data.HashMap.Strict.InsOrd (InsOrdHashMap)-import qualified Data.HashMap.Strict.InsOrd  as InsOrdHashMap-import Data.Text (Text)-import qualified Data.Text as Text-import GHC.TypeLits-import Network.HTTP.Media (MediaType)-import Servant.API-import Servant.API.Description (FoldDescription, reflectDescription)-import Servant.API.Modifiers (FoldRequired)-import Data.Singletons.Bool+import           Control.Lens+import           Data.Aeson+import           Data.HashMap.Strict.InsOrd             (InsOrdHashMap)+import qualified Data.HashMap.Strict.InsOrd             as InsOrdHashMap+import           Data.Monoid+import           Data.Proxy+import           Data.Singletons.Bool+import           Data.Swagger                           hiding (Header)+import qualified Data.Swagger                           as Swagger+import           Data.Swagger.Declare+import           Data.Text                              (Text)+import qualified Data.Text                              as Text+import           GHC.TypeLits+import           Network.HTTP.Media                     (MediaType)+import           Servant.API+import           Servant.API.Description                (FoldDescription,+                                                         reflectDescription)+import           Servant.API.Modifiers                  (FoldRequired) -import Servant.Swagger.Internal.TypeLevel.API+import           Servant.Swagger.Internal.TypeLevel.API  -- | Generate a Swagger specification for a servant API. --@@ -119,15 +123,15 @@ mkEndpointWithSchemaRef mref path _ = mempty   & paths.at path ?~     (mempty & method ?~ (mempty-      & produces ?~ MimeList contentTypes+      & produces ?~ MimeList responseContentTypes       & at code ?~ Inline (mempty             & schema  .~ mref             & headers .~ responseHeaders)))   where-    method          = swaggerMethod (Proxy :: Proxy method)-    code            = fromIntegral (natVal (Proxy :: Proxy status))-    contentTypes    = allContentType (Proxy :: Proxy cs)-    responseHeaders = toAllResponseHeaders (Proxy :: Proxy hs)+    method               = swaggerMethod (Proxy :: Proxy method)+    code                 = fromIntegral (natVal (Proxy :: Proxy status))+    responseContentTypes = allContentType (Proxy :: Proxy cs)+    responseHeaders      = toAllResponseHeaders (Proxy :: Proxy hs)  -- | Add parameter to every operation in the spec. addParam :: Param -> Swagger -> Swagger@@ -355,9 +359,9 @@   toAllResponseHeaders _ = mempty  instance (ToResponseHeader h, AllToResponseHeader hs) => AllToResponseHeader (h ': hs) where-  toAllResponseHeaders _ = InsOrdHashMap.insert hname header hdrs+  toAllResponseHeaders _ = InsOrdHashMap.insert headerName headerBS hdrs     where-      (hname, header) = toResponseHeader (Proxy :: Proxy h)+      (headerName, headerBS) = toResponseHeader (Proxy :: Proxy h)       hdrs = toAllResponseHeaders (Proxy :: Proxy hs)  instance AllToResponseHeader hs => AllToResponseHeader (HList hs) where
src/Servant/Swagger/Internal/Test.hs view
@@ -1,21 +1,27 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ConstraintKinds     #-}+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE RankNTypes          #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeOperators       #-} module Servant.Swagger.Internal.Test where -import Data.Aeson (ToJSON)-import Data.Swagger-import Data.Text (Text)-import Data.Typeable-import Test.Hspec-import Test.Hspec.QuickCheck-import Test.QuickCheck (Arbitrary)+import           Data.Aeson                         (ToJSON (..))+import           Data.Aeson.Encode.Pretty           (encodePretty)+import           Data.Swagger                       (Pattern, ToSchema,+                                                     toSchema)+import           Data.Swagger.Schema.Validation+import           Data.Text                          (Text)+import qualified Data.Text.Lazy                     as TL+import qualified Data.Text.Lazy.Encoding            as TL+import           Data.Typeable+import           Test.Hspec+import           Test.Hspec.QuickCheck+import           Test.QuickCheck                    (Arbitrary, Property,+                                                     counterexample, property) -import Servant.API-import Servant.Swagger.Internal.TypeLevel+import           Servant.API+import           Servant.Swagger.Internal.TypeLevel  -- $setup -- >>> import Control.Applicative@@ -47,8 +53,9 @@ -- <BLANKLINE> -- ToJSON matches ToSchema --   User+-- ... --   UserId--- <BLANKLINE>+-- ... -- Finished in ... seconds -- 2 examples, 0 failures --@@ -75,7 +82,7 @@   -> Spec validateEveryToJSON _ = props   (Proxy :: Proxy [ToJSON, ToSchema])-  (null . validateToJSON)+  (maybeCounterExample . prettyValidateWith validateToJSON)   (Proxy :: Proxy (BodyTypes JSON api))  -- | Verify that every type used with @'JSON'@ content type in a servant API@@ -88,7 +95,7 @@   -> Spec validateEveryToJSONWithPatternChecker checker _ = props   (Proxy :: Proxy [ToJSON, ToSchema])-  (null . validateToJSONWithPatternChecker checker)+  (maybeCounterExample . prettyValidateWith (validateToJSONWithPatternChecker checker))   (Proxy :: Proxy (BodyTypes JSON api))  -- * QuickCheck-related stuff@@ -101,21 +108,23 @@ --    context "read . show == id" $ --      props --        (Proxy :: Proxy [Eq, Show, Read])---        (\x -> read (show x) == x)+--        (\x -> read (show x) === x) --        (Proxy :: Proxy [Bool, Int, String]) -- :} -- <BLANKLINE> -- read . show == id --   Bool+-- ... --   Int+-- ... --   [Char]--- <BLANKLINE>+-- ... -- Finished in ... seconds -- 3 examples, 0 failures props :: forall p p'' cs xs. TMap (Every (Typeable ': Show ': Arbitrary ': cs)) xs =>-  p cs                                      -- ^ A list of constraints.-  -> (forall x. EveryTF cs x => x -> Bool)  -- ^ Property predicate.-  -> p'' xs                                 -- ^ A list of types.+  p cs                                          -- ^ A list of constraints.+  -> (forall x. EveryTF cs x => x -> Property)  -- ^ Property predicate.+  -> p'' xs                                     -- ^ A list of types.   -> Spec props _ f px = sequence_ specs   where@@ -123,5 +132,68 @@     specs = tmapEvery (Proxy :: Proxy (Typeable ': Show ': Arbitrary ': cs)) aprop px      aprop :: forall p' a. (EveryTF cs a, Typeable a, Show a, Arbitrary a) => p' a -> Spec-    aprop _ = prop (show (typeOf (undefined :: a))) (f :: a -> Bool)+    aprop _ = prop (show (typeOf (undefined :: a))) (f :: a -> Property) +-- | Pretty print validation errors+-- together with actual JSON and Swagger Schema+-- (using 'encodePretty').+--+-- >>> import Data.Aeson+-- >>> import Data.Foldable (traverse_)+-- >>> data Person = Person { name :: String, phone :: Integer } deriving (Generic)+-- >>> instance ToJSON Person where toJSON p = object [ "name" .= name p ]+-- >>> instance ToSchema Person+-- >>> let person = Person { name = "John", phone = 123456 }+-- >>> traverse_ putStrLn $ prettyValidateWith validateToJSON person+-- Validation against the schema fails:+--   * property "phone" is required, but not found in "{\"name\":\"John\"}"+-- <BLANKLINE>+-- JSON value:+-- {+--     "name": "John"+-- }+-- <BLANKLINE>+-- Swagger Schema:+-- {+--     "required": [+--         "name",+--         "phone"+--     ],+--     "type": "object",+--     "properties": {+--         "phone": {+--             "type": "integer"+--         },+--         "name": {+--             "type": "string"+--         }+--     }+-- }+-- <BLANKLINE>+--+-- FIXME: this belongs in "Data.Swagger.Schema.Validation" (in @swagger2@).+prettyValidateWith+  :: forall a. (ToJSON a, ToSchema a)+  => (a -> [ValidationError]) -> a -> Maybe String+prettyValidateWith f x =+  case f x of+    []      -> Nothing+    errors  -> Just $ unlines+      [ "Validation against the schema fails:"+      , unlines (map ("  * " ++) errors)+      , "JSON value:"+      , ppJSONString json+      , ""+      , "Swagger Schema:"+      , ppJSONString (toJSON schema)+      ]+  where+    ppJSONString = TL.unpack . TL.decodeUtf8 . encodePretty++    json   = toJSON x+    schema = toSchema (Proxy :: Proxy a)++-- | Provide a counterexample if there is any.+maybeCounterExample :: Maybe String -> Property+maybeCounterExample Nothing  = property True+maybeCounterExample (Just s) = counterexample s (property False)
src/Servant/Swagger/Internal/TypeLevel.hs view
@@ -4,6 +4,6 @@   module Servant.Swagger.Internal.TypeLevel.TMap, ) where -import Servant.Swagger.Internal.TypeLevel.API-import Servant.Swagger.Internal.TypeLevel.Every-import Servant.Swagger.Internal.TypeLevel.TMap+import           Servant.Swagger.Internal.TypeLevel.API+import           Servant.Swagger.Internal.TypeLevel.Every+import           Servant.Swagger.Internal.TypeLevel.TMap
src/Servant/Swagger/Internal/TypeLevel/API.hs view
@@ -1,15 +1,15 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ConstraintKinds      #-}+{-# LANGUAGE DataKinds            #-}+{-# LANGUAGE KindSignatures       #-}+{-# LANGUAGE PolyKinds            #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE TypeOperators        #-} {-# LANGUAGE UndecidableInstances #-} module Servant.Swagger.Internal.TypeLevel.API where -import Data.Type.Bool (If)-import Servant.API-import GHC.Exts (Constraint)+import           Data.Type.Bool (If)+import           GHC.Exts       (Constraint)+import           Servant.API  -- | Build a list of endpoints from an API. type family EndpointsList api where
src/Servant/Swagger/Internal/TypeLevel/Every.hs view
@@ -1,27 +1,27 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE InstanceSigs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE CPP                     #-}+{-# LANGUAGE ConstraintKinds         #-}+{-# LANGUAGE DataKinds               #-}+{-# LANGUAGE FlexibleContexts        #-}+{-# LANGUAGE FlexibleInstances       #-}+{-# LANGUAGE GADTs                   #-}+{-# LANGUAGE InstanceSigs            #-}+{-# LANGUAGE KindSignatures          #-}+{-# LANGUAGE MultiParamTypeClasses   #-}+{-# LANGUAGE PolyKinds               #-}+{-# LANGUAGE RankNTypes              #-}+{-# LANGUAGE ScopedTypeVariables     #-}+{-# LANGUAGE TypeFamilies            #-}+{-# LANGUAGE TypeOperators           #-}+{-# LANGUAGE UndecidableInstances    #-} #if __GLASGOW_HASKELL__ >= 800 {-# LANGUAGE UndecidableSuperClasses #-} #endif module Servant.Swagger.Internal.TypeLevel.Every where -import Data.Proxy-import GHC.Exts (Constraint)+import           Data.Proxy+import           GHC.Exts                                (Constraint) -import Servant.Swagger.Internal.TypeLevel.TMap+import           Servant.Swagger.Internal.TypeLevel.TMap  -- $setup -- >>> :set -XDataKinds
src/Servant/Swagger/Internal/TypeLevel/TMap.hs view
@@ -1,17 +1,17 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE KindSignatures        #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-} module Servant.Swagger.Internal.TypeLevel.TMap where -import Data.Proxy-import GHC.Exts (Constraint)+import           Data.Proxy+import           GHC.Exts   (Constraint)  -- $setup -- >>> :set -XDataKinds
src/Servant/Swagger/Test.hs view
@@ -10,4 +10,4 @@   validateEveryToJSONWithPatternChecker, ) where -import Servant.Swagger.Internal.Test+import           Servant.Swagger.Internal.Test
src/Servant/Swagger/TypeLevel.hs view
@@ -11,5 +11,5 @@   BodyTypes, ) where -import Servant.Swagger.Internal.TypeLevel+import           Servant.Swagger.Internal.TypeLevel 
+ test/Data/Aeson/QQ/Simple2.hs view
@@ -0,0 +1,24 @@+-- | Like "Data.Aeson.QQ" but without interpolation.+module Data.Aeson.QQ.Simple2 (aesonQQ) where++import           Data.Aeson (eitherDecode, Value)+import           Data.ByteString.Lazy.UTF8  as UTF8+import           Language.Haskell.TH+import           Language.Haskell.TH.Quote+import           Language.Haskell.TH.Syntax (Lift (..))+import           Prelude                    ()+import           Prelude.Compat++aesonQQ :: QuasiQuoter+aesonQQ = QuasiQuoter+    { quoteExp  = aesonExp+    , quotePat  = const $ error "No quotePat defined for jsonQQ"+    , quoteType = const $ error "No quoteType defined for jsonQQ"+    , quoteDec  = const $ error "No quoteDec defined for jsonQQ"+    }++aesonExp :: String -> ExpQ+aesonExp txt =+  case eitherDecode $ UTF8.fromString txt of+    Left err  -> error $ "Error in aesonExp: " ++ show err+    Right val -> lift (val :: Value)
test/Servant/SwaggerSpec.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE OverloadedStrings  #-} {-# LANGUAGE QuasiQuotes        #-} {-# LANGUAGE TypeOperators      #-}+{-# LANGUAGE PackageImports     #-} #if __GLASGOW_HASKELL__ == 708 {-# OPTIONS_GHC -fcontext-stack=31 #-} #endif@@ -12,7 +13,7 @@  import           Control.Lens import           Data.Aeson       (ToJSON(toJSON), Value, genericToJSON)-import           Data.Aeson.QQ+import           Data.Aeson.QQ.Simple2 -- aeson will have the Simple module soon import qualified Data.Aeson.Types as JSON import           Data.Char        (toLower) import           Data.Int         (Int64)