servant-server 0.14 → 0.14.1
raw patch · 9 files changed
+241/−153 lines, 9 filesdep ~QuickCheckdep ~basedep ~containers
Dependency ranges changed: QuickCheck, base, containers, doctest, network, servant
Files
- CHANGELOG.md +10/−0
- servant-server.cabal +9/−4
- src/Servant.hs +2/−2
- src/Servant/Server/Generic.hs +52/−0
- src/Servant/Server/Internal/Context.hs +1/−1
- src/Servant/Server/StaticFiles.hs +92/−0
- src/Servant/Utils/StaticFiles.hs +4/−84
- test/Servant/Server/StaticFilesSpec.hs +71/−0
- test/Servant/Utils/StaticFilesSpec.hs +0/−62
CHANGELOG.md view
@@ -1,6 +1,16 @@ [The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant-server/CHANGELOG.md) [Changelog for `servant` package contains significant entries for all core packages.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md) +0.14.1+------++- Merge in `servant-generic` (by [Patrick Chilton](https://github.com/chpatrick))+ into `servant` (`Servant.API.Generic`),+ `servant-client-code` (`Servant.Client.Generic`)+ and `servant-server` (`Servant.Server.Generic`).++- *servant-server* Deprecate `Servant.Utils.StaticUtils`, use `Servant.Server.StaticUtils`.+ 0.14 ----
servant-server.cabal view
@@ -1,5 +1,5 @@ name: servant-server-version: 0.14+version: 0.14.1 synopsis: A family of combinators for defining webservices APIs and serving them description: A family of combinators for defining webservices APIs and serving them@@ -47,6 +47,7 @@ Servant Servant.Server Servant.Server.Experimental.Auth+ Servant.Server.Generic Servant.Server.Internal Servant.Server.Internal.BasicAuth Servant.Server.Internal.Context@@ -54,6 +55,10 @@ Servant.Server.Internal.Router Servant.Server.Internal.RoutingApplication Servant.Server.Internal.ServantErr+ Servant.Server.StaticFiles++ -- deprecated+ exposed-modules: Servant.Utils.StaticFiles -- Bundled with GHC: Lower bound to not force re-installs@@ -75,7 +80,7 @@ -- Servant dependencies build-depends:- servant == 0.14.*+ servant >= 0.14.1 && <0.15 -- Other dependencies: Lower bound around what is in the latest Stackage LTS. -- Here can be exceptions if we really need features from the newer versions.@@ -133,12 +138,12 @@ Servant.Server.Internal.ContextSpec Servant.Server.Internal.RoutingApplicationSpec Servant.Server.RouterSpec+ Servant.Server.StaticFilesSpec Servant.Server.StreamingSpec Servant.Server.UsingContextSpec Servant.Server.UsingContextSpec.TestCombinators Servant.HoistSpec Servant.ServerSpec- Servant.Utils.StaticFilesSpec -- Dependencies inherited from the library. No need to specify bounds. build-depends:@@ -176,7 +181,7 @@ build-depends: base , servant-server- , doctest >= 0.15.0 && <0.16+ , doctest >= 0.15.0 && <0.17 type: exitcode-stdio-1.0 main-is: test/doctests.hs buildable: True
src/Servant.hs view
@@ -6,7 +6,7 @@ -- | For implementing servers for servant APIs. module Servant.Server, -- | Utilities on top of the servant core- module Servant.Utils.Links,+ module Servant.Links, module Servant.Utils.StaticFiles, -- | Useful re-exports Proxy(..),@@ -17,5 +17,5 @@ import Data.Proxy import Servant.API import Servant.Server-import Servant.Utils.Links+import Servant.Links import Servant.Utils.StaticFiles
+ src/Servant/Server/Generic.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+-- | @since 0.14.1+module Servant.Server.Generic (+ AsServerT,+ AsServer,+ genericServe,+ genericServer,+ genericServerT,+ ) where++import Data.Proxy+ (Proxy (..))++import Servant.API.Generic+import Servant.Server++-- | A type that specifies that an API record contains a server implementation.+data AsServerT (m :: * -> *)+instance GenericMode (AsServerT m) where+ type AsServerT m :- api = ServerT api m++type AsServer = AsServerT Handler++-- | Transform record of routes into a WAI 'Application'.+genericServe+ :: forall routes.+ ( HasServer (ToServantApi routes) '[]+ , GenericServant routes AsServer+ , Server (ToServantApi routes) ~ ToServant routes AsServer+ )+ => routes AsServer -> Application+genericServe = serve (Proxy :: Proxy (ToServantApi routes)) . genericServer++-- | Transform record of endpoints into a 'Server'.+genericServer+ :: GenericServant routes AsServer+ => routes AsServer+ -> ToServant routes AsServer+genericServer = toServant++genericServerT+ :: GenericServant routes (AsServerT m)+ => routes (AsServerT m)+ -> ToServant routes (AsServerT m)+genericServerT = toServant
src/Servant/Server/Internal/Context.hs view
@@ -18,7 +18,7 @@ -- | 'Context's are used to pass values to combinators. (They are __not__ meant -- to be used to pass parameters to your handlers, i.e. they should not replace -- any custom 'Control.Monad.Trans.Reader.ReaderT'-monad-stack that you're using--- with 'Servant.Utils.Enter'.) If you don't use combinators that+-- with 'hoistServer'.) If you don't use combinators that -- require any context entries, you can just use 'Servant.Server.serve' as always. -- -- If you are using combinators that require a non-empty 'Context' you have to
+ src/Servant/Server/StaticFiles.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE CPP #-}+-- | This module defines server-side handlers that lets you serve static files.+--+-- The most common needs for a web application are covered by+-- 'serveDirectoryWebApp`, but the other variants allow you to use+-- different `StaticSettings` and 'serveDirectoryWith' even allows you+-- to specify arbitrary 'StaticSettings' to be used for serving static files.+module Servant.Server.StaticFiles+ ( serveDirectoryWebApp+ , serveDirectoryWebAppLookup+ , serveDirectoryFileServer+ , serveDirectoryEmbedded+ , serveDirectoryWith+ , -- * Deprecated+ serveDirectory+ ) where++import Data.ByteString+ (ByteString)+import Network.Wai.Application.Static+import Servant.API.Raw+ (Raw)+import Servant.Server+ (ServerT, Tagged (..))+import System.FilePath+ (addTrailingPathSeparator)+#if !MIN_VERSION_wai_app_static(3,1,0)+import Filesystem.Path.CurrentOS+ (decodeString)+#endif+import WaiAppStatic.Storage.Filesystem+ (ETagLookup)++-- | Serve anything under the specified directory as a 'Raw' endpoint.+--+-- @+-- type MyApi = "static" :> Raw+--+-- server :: Server MyApi+-- server = serveDirectoryWebApp "\/var\/www"+-- @+--+-- would capture any request to @\/static\/\<something>@ and look for+-- @\<something>@ under @\/var\/www@.+--+-- It will do its best to guess the MIME type for that file, based on the extension,+-- and send an appropriate /Content-Type/ header if possible.+--+-- If your goal is to serve HTML, CSS and Javascript files that use the rest of the API+-- as a webapp backend, you will most likely not want the static files to be hidden+-- behind a /\/static\// prefix. In that case, remember to put the 'serveDirectoryWebApp'+-- handler in the last position, because /servant/ will try to match the handlers+-- in order.+--+-- Corresponds to the `defaultWebAppSettings` `StaticSettings` value.+serveDirectoryWebApp :: FilePath -> ServerT Raw m+serveDirectoryWebApp = serveDirectoryWith . defaultWebAppSettings . fixPath++-- | Same as 'serveDirectoryWebApp', but uses `defaultFileServerSettings`.+serveDirectoryFileServer :: FilePath -> ServerT Raw m+serveDirectoryFileServer = serveDirectoryWith . defaultFileServerSettings . fixPath++-- | Same as 'serveDirectoryWebApp', but uses 'webAppSettingsWithLookup'.+serveDirectoryWebAppLookup :: ETagLookup -> FilePath -> ServerT Raw m+serveDirectoryWebAppLookup etag =+ serveDirectoryWith . flip webAppSettingsWithLookup etag . fixPath++-- | Uses 'embeddedSettings'.+serveDirectoryEmbedded :: [(FilePath, ByteString)] -> ServerT Raw m+serveDirectoryEmbedded files = serveDirectoryWith (embeddedSettings files)++-- | Alias for 'staticApp'. Lets you serve a directory+-- with arbitrary 'StaticSettings'. Useful when you want+-- particular settings not covered by the four other+-- variants. This is the most flexible method.+serveDirectoryWith :: StaticSettings -> ServerT Raw m+serveDirectoryWith = Tagged . staticApp++-- | Same as 'serveDirectoryFileServer'. It used to be the only+-- file serving function in servant pre-0.10 and will be kept+-- around for a few versions, but is deprecated.+serveDirectory :: FilePath -> ServerT Raw m+serveDirectory = serveDirectoryFileServer+{-# DEPRECATED serveDirectory "Use serveDirectoryFileServer instead" #-}++fixPath :: FilePath -> FilePath+fixPath =+#if MIN_VERSION_wai_app_static(3,1,0)+ addTrailingPathSeparator+#else+ decodeString . addTrailingPathSeparator+#endif
src/Servant/Utils/StaticFiles.hs view
@@ -1,86 +1,6 @@-{-# LANGUAGE CPP #-}--- | This module defines server-side handlers that lets you serve static files.------ The most common needs for a web application are covered by--- 'serveDirectoryWebApp`, but the other variants allow you to use--- different `StaticSettings` and 'serveDirectoryWith' even allows you--- to specify arbitrary 'StaticSettings' to be used for serving static files. module Servant.Utils.StaticFiles- ( serveDirectoryWebApp- , serveDirectoryWebAppLookup- , serveDirectoryFileServer- , serveDirectoryEmbedded- , serveDirectoryWith- , -- * Deprecated- serveDirectory- ) where--import Data.ByteString (ByteString)-import Network.Wai.Application.Static-import Servant.API.Raw (Raw)-import Servant.Server (ServerT, Tagged (..))-import System.FilePath (addTrailingPathSeparator)-#if !MIN_VERSION_wai_app_static(3,1,0)-import Filesystem.Path.CurrentOS (decodeString)-#endif-import WaiAppStatic.Storage.Filesystem (ETagLookup)---- | Serve anything under the specified directory as a 'Raw' endpoint.------ @--- type MyApi = "static" :> Raw------ server :: Server MyApi--- server = serveDirectoryWebApp "\/var\/www"--- @------ would capture any request to @\/static\/\<something>@ and look for--- @\<something>@ under @\/var\/www@.------ It will do its best to guess the MIME type for that file, based on the extension,--- and send an appropriate /Content-Type/ header if possible.------ If your goal is to serve HTML, CSS and Javascript files that use the rest of the API--- as a webapp backend, you will most likely not want the static files to be hidden--- behind a /\/static\// prefix. In that case, remember to put the 'serveDirectoryWebApp'--- handler in the last position, because /servant/ will try to match the handlers--- in order.------ Corresponds to the `defaultWebAppSettings` `StaticSettings` value.-serveDirectoryWebApp :: FilePath -> ServerT Raw m-serveDirectoryWebApp = serveDirectoryWith . defaultWebAppSettings . fixPath---- | Same as 'serveDirectoryWebApp', but uses `defaultFileServerSettings`.-serveDirectoryFileServer :: FilePath -> ServerT Raw m-serveDirectoryFileServer = serveDirectoryWith . defaultFileServerSettings . fixPath---- | Same as 'serveDirectoryWebApp', but uses 'webAppSettingsWithLookup'.-serveDirectoryWebAppLookup :: ETagLookup -> FilePath -> ServerT Raw m-serveDirectoryWebAppLookup etag =- serveDirectoryWith . flip webAppSettingsWithLookup etag . fixPath---- | Uses 'embeddedSettings'.-serveDirectoryEmbedded :: [(FilePath, ByteString)] -> ServerT Raw m-serveDirectoryEmbedded files = serveDirectoryWith (embeddedSettings files)---- | Alias for 'staticApp'. Lets you serve a directory--- with arbitrary 'StaticSettings'. Useful when you want--- particular settings not covered by the four other--- variants. This is the most flexible method.-serveDirectoryWith :: StaticSettings -> ServerT Raw m-serveDirectoryWith = Tagged . staticApp---- | Same as 'serveDirectoryFileServer'. It used to be the only--- file serving function in servant pre-0.10 and will be kept--- around for a few versions, but is deprecated.-serveDirectory :: FilePath -> ServerT Raw m-serveDirectory = serveDirectoryFileServer-{-# DEPRECATED serveDirectory "Use serveDirectoryFileServer instead" #-}+ {-# DEPRECATED "Use Servant.ServerStaticFiles." #-}+ ( module Servant.Server.StaticFiles )+ where -fixPath :: FilePath -> FilePath-fixPath =-#if MIN_VERSION_wai_app_static(3,1,0)- addTrailingPathSeparator-#else- decodeString . addTrailingPathSeparator-#endif+import Servant.Server.StaticFiles
+ test/Servant/Server/StaticFilesSpec.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeOperators #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Servant.Server.StaticFilesSpec where++import Control.Exception+ (bracket)+import Data.Proxy+ (Proxy (Proxy))+import Network.Wai+ (Application)+import System.Directory+ (createDirectory, getCurrentDirectory, setCurrentDirectory)+import System.IO.Temp+ (withSystemTempDirectory)+import Test.Hspec+ (Spec, around_, describe, it)+import Test.Hspec.Wai+ (get, shouldRespondWith, with)++import Servant.API+ ((:<|>) ((:<|>)), (:>), Capture, Get, JSON, Raw)+import Servant.Server+ (Server, serve)+import Servant.Server.StaticFiles+ (serveDirectoryFileServer)+import Servant.ServerSpec+ (Person (Person))++type Api =+ "dummy_api" :> Capture "person_name" String :> Get '[JSON] Person+ :<|> "static" :> Raw+++api :: Proxy Api+api = Proxy++app :: Application+app = serve api server++server :: Server Api+server =+ (\ name_ -> return (Person name_ 42))+ :<|> serveDirectoryFileServer "static"++withStaticFiles :: IO () -> IO ()+withStaticFiles action = withSystemTempDirectory "servant-test" $ \ tmpDir ->+ bracket (setup tmpDir) teardown (const action)+ where+ setup tmpDir = do+ outer <- getCurrentDirectory+ setCurrentDirectory tmpDir+ createDirectory "static"+ writeFile "static/foo.txt" "bar"+ writeFile "static/index.html" "index"+ return outer++ teardown outer = do+ setCurrentDirectory outer++spec :: Spec+spec = do+ around_ withStaticFiles $ with (return app) $ do+ describe "serveDirectory" $ do+ it "successfully serves files" $ do+ get "/static/foo.txt" `shouldRespondWith` "bar"++ it "serves the contents of index.html when requesting the root of a directory" $ do+ get "/static/" `shouldRespondWith` "index"
− test/Servant/Utils/StaticFilesSpec.hs
@@ -1,62 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeOperators #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module Servant.Utils.StaticFilesSpec where--import Control.Exception (bracket)-import Data.Proxy (Proxy (Proxy))-import Network.Wai (Application)-import System.Directory (createDirectory,- getCurrentDirectory,- setCurrentDirectory)-import System.IO.Temp (withSystemTempDirectory)-import Test.Hspec (Spec, around_, describe, it)-import Test.Hspec.Wai (get, shouldRespondWith, with)--import Servant.API ((:<|>) ((:<|>)), Capture, Get, Raw, (:>), JSON)-import Servant.Server (Server, serve)-import Servant.ServerSpec (Person (Person))-import Servant.Utils.StaticFiles (serveDirectoryFileServer)--type Api =- "dummy_api" :> Capture "person_name" String :> Get '[JSON] Person- :<|> "static" :> Raw---api :: Proxy Api-api = Proxy--app :: Application-app = serve api server--server :: Server Api-server =- (\ name_ -> return (Person name_ 42))- :<|> serveDirectoryFileServer "static"--withStaticFiles :: IO () -> IO ()-withStaticFiles action = withSystemTempDirectory "servant-test" $ \ tmpDir ->- bracket (setup tmpDir) teardown (const action)- where- setup tmpDir = do- outer <- getCurrentDirectory- setCurrentDirectory tmpDir- createDirectory "static"- writeFile "static/foo.txt" "bar"- writeFile "static/index.html" "index"- return outer-- teardown outer = do- setCurrentDirectory outer--spec :: Spec-spec = do- around_ withStaticFiles $ with (return app) $ do- describe "serveDirectory" $ do- it "successfully serves files" $ do- get "/static/foo.txt" `shouldRespondWith` "bar"-- it "serves the contents of index.html when requesting the root of a directory" $ do- get "/static/" `shouldRespondWith` "index"