yam 0.5.2 → 0.5.3
raw patch · 9 files changed
+256/−203 lines, 9 filesdep +http-typesdep +lensdep +swagger2dep −yamdep ~QuickCheckdep ~aesondep ~bytestring
Dependencies added: http-types, lens, swagger2, unliftio-core
Dependencies removed: yam
Dependency ranges changed: QuickCheck, aeson, bytestring, data-default, fast-logger, monad-logger, mtl, random, reflection, salak, servant-server, servant-swagger, servant-swagger-ui, text, vault, wai, warp
Files
- demo/Main.hs +0/−30
- src/Yam.hs +2/−2
- src/Yam/Auth.hs +49/−0
- src/Yam/Internal.hs +12/−33
- src/Yam/Logger.hs +45/−2
- src/Yam/Swagger.hs +11/−2
- src/Yam/Trace.hs +3/−9
- src/Yam/Types.hs +23/−11
- yam.cabal +111/−114
− demo/Main.hs
@@ -1,30 +0,0 @@-module Main where--import Control.Monad.Logger.CallStack-import qualified Data.Salak as S-import Servant-import Yam--type UserApi- = "users" :> Get '[JSON] Text- :<|> "users" :> "error" :> Get '[JSON] Text- :<|> "users" :> "servant" :> Get '[JSON] Text--service :: ServerT UserApi App-service = userService :<|> errorService :<|> servantService--userService :: App Text-userService = do- logInfo $ "Hello: "- return "Hello"--errorService :: App Text-errorService = logError "No" >> return "No"--servantService :: App Text-servantService = throwS err401 "Servant"--main :: IO ()-main = do- p <- S.defaultPropertiesWithFile "yam_test.yml"- start p [] (Proxy :: Proxy UserApi) service
src/Yam.hs view
@@ -1,7 +1,7 @@ module Yam( module Yam.Internal- -- , module Yam.DataSource+ , module Yam.Auth ) where --- import Yam.DataSource+import Yam.Auth import Yam.Internal
+ src/Yam/Auth.hs view
@@ -0,0 +1,49 @@+module Yam.Auth where+import Control.Lens+import Data.Default+import Data.Swagger+import Servant.Server.Internal.RoutingApplication+import Servant.Swagger+import Servant.Swagger.Internal+import System.IO.Unsafe (unsafePerformIO)+import Yam.Internal hiding (name)++data CheckAuth (principal :: *)++newtype AuthChecker principal = AuthChecker { runCheckAuth :: Request -> App principal }++instance Default (AuthChecker principal) where+ def = AuthChecker $ \_ -> throwS err401 "No Auth Checker"++class HasAuthKey principal where+ authKey :: Key (AuthChecker principal)+ authKey = unsafePerformIO newKey++instance ( HasContextEntry context Env+ , HasServer api context+ , HasAuthKey principal)+ => HasServer (CheckAuth principal :> api) context where+ type ServerT (CheckAuth principal :> api) m = principal -> ServerT api m+ hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy :: Proxy api) pc nt . s+ route _ context server = route (Proxy :: Proxy api) context $ server `addAuthCheck` authCheck+ where+ env :: Env+ env = getContextEntry context+ checker :: Request -> App principal+ checker = runCheckAuth $ reqAttr authKey env+ authCheck :: DelayedIO principal+ authCheck = withRequest $ \req -> liftIO $ runAppM env { reqAttributes = Just (vault req)} (checker req)++instance (HasSwagger api, ToParamSchema principal) => HasSwagger (CheckAuth principal :> api) where+ toSwagger _ = toSwagger (Proxy :: Proxy api)+ & addParam param+ where+ param = mempty+ & Data.Swagger.name .~ "Authorization"+ & required ?~ True+ & schema .~ ParamOther (mempty+ & in_ .~ ParamHeader+ & paramSchema .~ toParamSchema (Proxy :: Proxy principal))++authAppMiddleware :: HasAuthKey principal => AuthChecker principal -> AppMiddleware+authAppMiddleware = simpleAppMiddleware (True, "Auth Plugin") authKey
src/Yam/Internal.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ImplicitParams #-} {-# LANGUAGE NoPolyKinds #-} module Yam.Internal( -- * Application Functions@@ -10,19 +9,15 @@ , module Yam.Types , SwaggerConfig(..) -- * Utilities- , throwS , readConf- , getLogger ) where import Control.Exception hiding (Handler) import qualified Data.ByteString.Lazy.Char8 as B import qualified Data.Salak as S import qualified Data.Vault.Lazy as L-import GHC.Stack import Network.Wai.Handler.Warp (run) import Servant.Swagger-import System.IO.Unsafe (unsafePerformIO) import Yam.Logger import Yam.Swagger import Yam.Trace@@ -30,46 +25,30 @@ type App = AppM IO -runApp :: LogFunc -> Env -> App a -> Handler a-runApp a b c = do- res :: Either SomeException a <- liftIO $ try (runAppM a b c)+runApp :: Env -> App a -> Handler a+runApp b c = do+ res :: Either SomeException a <- liftIO $ try (runAppM b c) case res of Left e -> throwError $ fromMaybe err400 { errBody = B.pack $ show e } (fromException e :: Maybe ServantErr) Right r -> return r -throwS :: (HasCallStack, MonadIO m) => ServantErr -> Text -> AppM m a-throwS e msg = do- logErrorCS ?callStack msg- lift $ throw e--{-# NOINLINE loggerKey #-}-loggerKey :: Key LogFunc-loggerKey = unsafePerformIO newKey--getLogger :: Env -> Maybe LogFunc-getLogger env =- let trace :: Maybe TraceLog = getAttr traceKey env- logger :: Maybe LogFunc = getAttr loggerKey env- {-# INLINE nlf #-}- nlf x (Just t) = addTrace x t- nlf x _ = x- in (`nlf` trace) <$> logger- startYam :: forall api. (HasSwagger api, HasServer api '[Env]) => AppConfig -> SwaggerConfig -> LogConfig -> Bool+ -> Version -> [AppMiddleware] -> Proxy api -> ServerT api App -> IO ()-startYam ac@AppConfig{..} sw@SwaggerConfig{..} logConfig enableTrace middlewares proxy server+startYam ac@AppConfig{..} sw@SwaggerConfig{..} logConfig enableTrace vs middlewares proxy server = withLogger name logConfig $ do logInfo $ "Start Service [" <> name <> "] ..." logger <- askLoggerIO- (runAM $ foldr1 (<>) (traceMiddleware enableTrace : middlewares)) (Env (L.insert loggerKey logger L.empty) Nothing ac) $ \(env, middleware) -> do+ let act = runAM $ foldr1 (<>) (traceMiddleware enableTrace : middlewares)+ act (setLogger logger $ Env L.empty Nothing ac) $ \(env, middleware) -> do let cxt = env :. EmptyContext pCxt = Proxy :: Proxy '[Env] portText = showText port@@ -80,15 +59,15 @@ logInfo $ "Servant started on port(s): " <> portText lift $ run port $ middleware- $ serveWithContextAndSwagger sw proxy' cxt- $ hoistServerWithContext proxy' pCxt (runApp logger env) server'+ $ serveWithContextAndSwagger sw ac vs proxy' cxt+ $ hoistServerWithContext proxy' pCxt (runApp env) server' runRequest :: (HasServer api context) => Proxy api -> Proxy context -> ServerT api App -> Vault -> ServerT api App runRequest p pc a v = hoistServerWithContext p pc go a where {-# INLINE go #-} go :: App a -> App a- go = withAppM (\(env,lf) -> let env' = env { reqAttributes = Just v} in (env', fromMaybe lf $ getLogger env'))+ go = withAppM (\env -> env { reqAttributes = Just v}) readConf :: (Default a, S.FromProperties a) => Text -> S.Properties -> a readConf k p = fromMaybe def $ S.lookup k p@@ -96,13 +75,13 @@ start :: forall api. (HasSwagger api, HasServer api '[Env]) => S.Properties+ -> Version -> [AppMiddleware] -> Proxy api -> ServerT api App -> IO ()-start p middlewares proxy service = startYam+start p = startYam (readConf "yam.application" p) (readConf "yam.swagger" p) (readConf "yam.logging" p) (fromMaybe True $ S.lookup "yam.trace.enabled" p)- middlewares proxy service
src/Yam/Logger.hs view
@@ -1,13 +1,20 @@+{-# LANGUAGE ImplicitParams #-} module Yam.Logger( -- * Logger Function withLogger- , addTrace+ , setLogger+ , setExtendLog+ , extensionLogKey+ , throwS , LogConfig(..) ) where -import Control.Exception (bracket)+import Control.Exception (bracket, throw) import Control.Monad (when)+import Control.Monad.Reader import qualified Data.Text as T+import GHC.Stack+import System.IO.Unsafe (unsafePerformIO) import System.Log.FastLogger import Yam.Types @@ -66,3 +73,39 @@ addTrace :: LogFunc -> Text -> LogFunc addTrace f tid a b c d = f a b c ("[" <> toLogStr tid <> "] " <> d)++{-# NOINLINE loggerKey #-}+loggerKey :: Key LogFunc+loggerKey = unsafePerformIO newKey++{-# NOINLINE extensionLogKey #-}+extensionLogKey :: Key Text+extensionLogKey = unsafePerformIO newKey++setExtendLog :: (Text -> Text) -> Env -> Env+setExtendLog f env = let mt = fromMaybe "" $ getAttr extensionLogKey env in setAttr extensionLogKey (f mt) env++setLogger :: LogFunc -> Env -> Env+setLogger = setAttr loggerKey++getLogger :: Env -> LogFunc+getLogger env =+ let trace :: Maybe Text = getAttr extensionLogKey env+ logger :: Maybe LogFunc = getAttr loggerKey env+ {-# INLINE nlf #-}+ nlf x (Just t) = addTrace x t+ nlf x _ = x+ in maybe (\_ _ _ _ -> return ()) (`nlf` trace) logger++instance MonadIO m => MonadLogger (AppM m) where+ monadLoggerLog a b c d = do+ env <- ask+ liftIO $ getLogger env a b c $ toLogStr d++instance (MonadIO m) => MonadLoggerIO (AppM m) where+ askLoggerIO = asks getLogger++throwS :: (HasCallStack, MonadIO m) => ServantErr -> Text -> AppM m a+throwS e msg = do+ logErrorCS ?callStack msg+ lift $ throw e
src/Yam/Swagger.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE NoPolyKinds #-} module Yam.Swagger where +import Control.Lens hiding (Context) import Data.Reflection+import Data.Swagger hiding (name, port) import GHC.TypeLits import Servant.Swagger import Servant.Swagger.UI@@ -27,11 +29,13 @@ serveWithContextAndSwagger :: (HasSwagger api, HasServer api context) => SwaggerConfig+ -> AppConfig+ -> Version -> Proxy api -> Context context -> ServerT api Handler -> Application-serveWithContextAndSwagger SwaggerConfig{..} proxy cxt api =+serveWithContextAndSwagger SwaggerConfig{..} AppConfig{..} versions proxy cxt api = if enabled then reifySymbol urlDir $ \pd -> reifySymbol urlSchema $ \ps -> go (pd,ps) proxy cxt api else serveWithContext proxy cxt api@@ -46,4 +50,9 @@ g2 :: (Proxy d, Proxy s) -> Proxy (SAPI d s api) g2 _ = Proxy g3 :: HasSwagger api => Proxy api -> Server api -> Proxy (SAPI d s api) -> Server (SAPI d s api)- g3 p a _ = swaggerSchemaUIServer (toSwagger p) :<|> a+ g3 p a _ = swaggerSchemaUIServer (g4 $ toSwagger p) :<|> a+ g4 s = s+ & info .~ (mempty+ & title .~ (name <> " API Documents")+ & version .~ pack (showVersion versions))+ & host ?~ Host "http://localhost" (Just $ fromIntegral port)
src/Yam/Trace.hs view
@@ -1,21 +1,15 @@ module Yam.Trace where -import qualified Data.Vault.Lazy as L+import qualified Data.Vault.Lazy as L import Network.Wai-import System.IO.Unsafe (unsafePerformIO)+import Yam.Logger import Yam.Types -type TraceLog = Text--{-# NOINLINE traceKey #-}-traceKey :: Key TraceLog-traceKey = unsafePerformIO newKey- traceMw :: Middleware traceMw app req resH = do traceId <- randomString 12 let h = ("X-TRACE-ID",encodeUtf8 traceId)- app req {vault = L.insert traceKey traceId (vault req)} (resH . mapResponseHeaders (h:))+ app req {vault = L.insert extensionLogKey traceId (vault req)} (resH . mapResponseHeaders (h:)) traceMiddleware :: Bool -> AppMiddleware traceMiddleware enabled = simpleWebMiddleware (enabled, "Trace") traceMw
src/Yam/Types.hs view
@@ -3,7 +3,6 @@ -- * Environment AppConfig(..) , Env(..)- , AppEnv , getAttr , setAttr , reqAttr@@ -35,6 +34,7 @@ , Text , pack , encodeUtf8+ , decodeUtf8 , MonadIO , liftIO , withReaderT@@ -43,17 +43,22 @@ , module Servant , module Data.Aeson , module Data.Word+ , module Data.Function+ , module Data.Version ) where +import Control.Monad.IO.Unlift import Control.Monad.Logger.CallStack import Control.Monad.Reader import Data.Aeson import Data.Default+import Data.Function import Data.Maybe import Data.Text (Text, justifyRight, pack)-import Data.Text.Encoding (encodeUtf8)+import Data.Text.Encoding (decodeUtf8, encodeUtf8) import Data.Vault.Lazy (Key, newKey) import qualified Data.Vault.Lazy as L+import Data.Version import Data.Word import GHC.Stack import Network.Wai@@ -97,19 +102,25 @@ Just av -> Env attributes (Just $ L.insert k v av) application _ -> Env (L.insert k v attributes) reqAttributes application -type AppM m = LoggingT (ReaderT Env m)-type AppEnv = (Env, LogFunc)+newtype AppM m a = AppM { runAppM' :: ReaderT Env m a } deriving (Functor, Applicative, Monad, MonadTrans, MonadIO) type LogFunc = Loc -> LogSource -> LogLevel -> LogStr -> IO () -runAppM :: LogFunc -> Env -> AppM m a -> m a-runAppM lf env a = runReaderT (runLoggingT a lf) env+runAppM :: Env -> AppM m a -> m a+runAppM e a = runReaderT (runAppM' a) e -withAppM :: MonadIO m => (AppEnv -> AppEnv) -> AppM m a -> AppM m a+instance Monad m => MonadReader Env (AppM m) where+ ask = AppM ask+ local f (AppM a) = AppM $ local f a++instance MonadUnliftIO m => MonadUnliftIO (AppM m) where+ withRunInIO f = do+ env <- ask+ lift $ withRunInIO (\g -> f $ g . runAppM env)++withAppM :: MonadIO m => (Env -> Env) -> AppM m a -> AppM m a withAppM f a = do- lf <- askLoggerIO env <- ask- let (e,l) = f (env,lf)- lift . lift $ runAppM l e a+ lift $ runAppM (f env) a askApp :: Monad m => AppM m AppConfig askApp = asks application@@ -121,7 +132,7 @@ askAttr = asks . getAttr withAttr :: MonadIO m => Key a -> a -> AppM m b -> AppM m b-withAttr k v = withAppM (\(env,lf) -> (setAttr k v env, lf))+withAttr k v = withAppM (setAttr k v) -- | Application Middleware newtype AppMiddleware = AppMiddleware {runAM :: Env -> ((Env, Middleware)-> LoggingT IO ()) -> LoggingT IO ()}@@ -159,3 +170,4 @@ {-# INLINE showText #-} showText :: Show a => a -> Text showText = pack . show+
yam.cabal view
@@ -1,122 +1,119 @@ cabal-version: 1.12---- This file has been generated from package.yaml by hpack version 0.31.1.------ see: https://github.com/sol/hpack------ hash: 8354a1cbffc8b45ccba09be46e0df544e4e479ad6c5062ac6650d1187e8312ae--name: yam-version: 0.5.2-synopsis: Yam Web-category: Web-homepage: https://github.com/leptonyu/yam/yam#readme-author: Daniel YU-maintainer: Daniel YU <leptonyu@gmail.com>-copyright: (c) 2018 Daniel YU-license: BSD3-license-file: LICENSE-build-type: Simple+name: yam+version: 0.5.3+license: BSD3+license-file: LICENSE+copyright: (c) 2018 Daniel YU+maintainer: Daniel YU <leptonyu@gmail.com>+author: Daniel YU+homepage: https://github.com/leptonyu/yam/yam#readme+synopsis: Yam Web+category: Web+build-type: Simple extra-source-files: README.md yam_test.yml library- exposed-modules:- Yam- Yam.Internal- other-modules:- Yam.Types- Yam.Logger- Yam.Swagger- Yam.Trace- hs-source-dirs:- src- default-extensions: AutoDeriveTypeable BangPatterns BinaryLiterals ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable DuplicateRecordFields DoAndIfThenElse EmptyDataDecls ExistentialQuantification FlexibleContexts FlexibleInstances FunctionalDependencies GADTs GeneralizedNewtypeDeriving InstanceSigs KindSignatures LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns OverloadedStrings PartialTypeSignatures PatternGuards PolyKinds RankNTypes RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections TypeApplications TypeFamilies TypeOperators TypeSynonymInstances ViewPatterns- ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -fno-warn-orphans -fno-warn-missing-signatures- build-depends:- aeson- , base >=4.7 && <5- , bytestring- , data-default- , fast-logger- , monad-logger- , mtl- , random- , reflection- , salak- , servant-server- , servant-swagger- , servant-swagger-ui- , text- , vault- , wai- , warp- default-language: Haskell2010--executable yam- main-is: Main.hs- other-modules:- Paths_yam- hs-source-dirs:- demo- default-extensions: AutoDeriveTypeable BangPatterns BinaryLiterals ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable DuplicateRecordFields DoAndIfThenElse EmptyDataDecls ExistentialQuantification FlexibleContexts FlexibleInstances FunctionalDependencies GADTs GeneralizedNewtypeDeriving InstanceSigs KindSignatures LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns OverloadedStrings PartialTypeSignatures PatternGuards PolyKinds RankNTypes RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections TypeApplications TypeFamilies TypeOperators TypeSynonymInstances ViewPatterns- ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -fno-warn-orphans -fno-warn-missing-signatures- build-depends:- aeson- , base >=4.7 && <5- , bytestring- , data-default- , fast-logger- , monad-logger- , mtl- , random- , reflection- , salak- , servant-server- , servant-swagger- , servant-swagger-ui- , text- , vault- , wai- , warp- , yam- default-language: Haskell2010+ exposed-modules:+ Yam+ Yam.Internal+ Yam.Auth+ hs-source-dirs: src+ other-modules:+ Yam.Types+ Yam.Logger+ Yam.Swagger+ Yam.Trace+ default-language: Haskell2010+ default-extensions: AutoDeriveTypeable BangPatterns BinaryLiterals+ ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable+ DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable+ DuplicateRecordFields DoAndIfThenElse EmptyDataDecls+ ExistentialQuantification FlexibleContexts FlexibleInstances+ FunctionalDependencies GADTs GeneralizedNewtypeDeriving+ InstanceSigs KindSignatures LambdaCase MonadFailDesugaring+ MultiParamTypeClasses MultiWayIf NamedFieldPuns OverloadedStrings+ PartialTypeSignatures PatternGuards PolyKinds RankNTypes+ RecordWildCards ScopedTypeVariables StandaloneDeriving+ TupleSections TypeApplications TypeFamilies TypeOperators+ TypeSynonymInstances ViewPatterns+ ghc-options: -Wall -Wcompat -Wincomplete-record-updates+ -Wincomplete-uni-patterns -Wredundant-constraints -fno-warn-orphans+ -fno-warn-missing-signatures+ build-depends:+ aeson >=1.4.2.0 && <1.5,+ base >=4.7 && <5,+ bytestring >=0.10.8.2 && <0.11,+ data-default >=0.7.1.1 && <0.8,+ fast-logger >=2.4.13 && <2.5,+ http-types >=0.12.2 && <0.13,+ lens ==4.17.*,+ monad-logger >=0.3.30 && <0.4,+ mtl >=2.2.2 && <2.3,+ random ==1.1.*,+ reflection >=2.1.4 && <2.2,+ salak >=0.1.4 && <0.2,+ servant-server ==0.15.*,+ servant-swagger >=1.1.7 && <1.2,+ servant-swagger-ui >=0.3.2.3.19.3 && <0.4,+ swagger2 >=2.3.1 && <2.4,+ text >=1.2.3.1 && <1.3,+ unliftio-core >=0.1.2.0 && <0.2,+ vault >=0.3.1.2 && <0.4,+ wai >=3.2.1.2 && <3.3,+ warp >=3.2.25 && <3.3 test-suite spec- type: exitcode-stdio-1.0- main-is: Spec.hs- other-modules:- Yam- Yam.Internal- Yam.Logger- Yam.Swagger- Yam.Trace- Yam.Types- Paths_yam- hs-source-dirs:- test- src- default-extensions: AutoDeriveTypeable BangPatterns BinaryLiterals ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable DuplicateRecordFields DoAndIfThenElse EmptyDataDecls ExistentialQuantification FlexibleContexts FlexibleInstances FunctionalDependencies GADTs GeneralizedNewtypeDeriving InstanceSigs KindSignatures LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns OverloadedStrings PartialTypeSignatures PatternGuards PolyKinds RankNTypes RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections TypeApplications TypeFamilies TypeOperators TypeSynonymInstances ViewPatterns- ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -fno-warn-orphans -fno-warn-missing-signatures- build-depends:- QuickCheck- , aeson- , base >=4.7 && <5- , bytestring- , data-default- , fast-logger- , hspec ==2.*- , monad-logger- , mtl- , random- , reflection- , salak- , servant-server- , servant-swagger- , servant-swagger-ui- , text- , vault- , wai- , warp- default-language: Haskell2010+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs: test src+ other-modules:+ Yam+ Yam.Auth+ Yam.Internal+ Yam.Logger+ Yam.Swagger+ Yam.Trace+ Yam.Types+ Paths_yam+ default-language: Haskell2010+ default-extensions: AutoDeriveTypeable BangPatterns BinaryLiterals+ ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable+ DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable+ DuplicateRecordFields DoAndIfThenElse EmptyDataDecls+ ExistentialQuantification FlexibleContexts FlexibleInstances+ FunctionalDependencies GADTs GeneralizedNewtypeDeriving+ InstanceSigs KindSignatures LambdaCase MonadFailDesugaring+ MultiParamTypeClasses MultiWayIf NamedFieldPuns OverloadedStrings+ PartialTypeSignatures PatternGuards PolyKinds RankNTypes+ RecordWildCards ScopedTypeVariables StandaloneDeriving+ TupleSections TypeApplications TypeFamilies TypeOperators+ TypeSynonymInstances ViewPatterns+ ghc-options: -Wall -Wcompat -Wincomplete-record-updates+ -Wincomplete-uni-patterns -Wredundant-constraints -fno-warn-orphans+ -fno-warn-missing-signatures+ build-depends:+ QuickCheck >=2.12.6.1 && <2.13,+ aeson >=1.4.2.0 && <1.5,+ base >=4.7 && <5,+ bytestring >=0.10.8.2 && <0.11,+ data-default >=0.7.1.1 && <0.8,+ fast-logger >=2.4.13 && <2.5,+ hspec ==2.*,+ http-types >=0.12.2 && <0.13,+ lens ==4.17.*,+ monad-logger >=0.3.30 && <0.4,+ mtl >=2.2.2 && <2.3,+ random ==1.1.*,+ reflection >=2.1.4 && <2.2,+ salak >=0.1.4 && <0.2,+ servant-server ==0.15.*,+ servant-swagger >=1.1.7 && <1.2,+ servant-swagger-ui >=0.3.2.3.19.3 && <0.4,+ swagger2 >=2.3.1 && <2.4,+ text >=1.2.3.1 && <1.3,+ unliftio-core >=0.1.2.0 && <0.2,+ vault >=0.3.1.2 && <0.4,+ wai >=3.2.1.2 && <3.3,+ warp >=3.2.25 && <3.3