on master help sign in
Revamp static file serving module.
8efabedAlp Mestanogullari
doc/tutorial/Javascript.lhs+1−1
@@ -136,7 +136,7 @@ server = randomPoint
136
136
137server' :: Server API'
137server' :: Server API'
138server' = server
138server' = server
139− :<|> serveDirectory "static"
139+ :<|> serveDirectoryWebApp "static"
140
140
141app :: Application
141app :: Application
142app = serve api' server'
142app = serve api' server'
doc/tutorial/Server.lhs+7−3
@@ -787,10 +787,10 @@ directory serving WAI application, namely:
787
787
788``` haskell ignore
788``` haskell ignore
789-- exported by Servant and Servant.Server
789-- exported by Servant and Servant.Server
790−serveDirectory :: FilePath -> Server Raw
790+serveDirectoryWebApp :: FilePath -> Server Raw
791```
791```
792
792
793−`serveDirectory`'s argument must be a path to a valid directory.
793+`serveDirectoryWebApp`'s argument must be a path to a valid directory.
794
794
795Here's an example API that will serve some static files:
795Here's an example API that will serve some static files:
796
796
@@ -807,7 +807,7 @@ staticAPI = Proxy
807
807
808``` haskell
808``` haskell
809server7 :: Server StaticAPI
809server7 :: Server StaticAPI
810−server7 = serveDirectory "static-files"
810+server7 = serveDirectoryWebApp "static-files"
811
811
812app3 :: Application
812app3 :: Application
813app3 = serve staticAPI server7
813app3 = serve staticAPI server7
@@ -821,6 +821,10 @@ In other words: If a client requests `/static/foo.txt`, the server will look for
821`./static-files/foo.txt`. If that file exists it'll succeed and serve the file.
821`./static-files/foo.txt`. If that file exists it'll succeed and serve the file.
822If it doesn't exist, the handler will fail with a `404` status code.
822If it doesn't exist, the handler will fail with a `404` status code.
823
823
824+`serveDirectoryWebApp` uses some standard settings that fit the use case of
825+serving static files for most web apps. You can find out about the other
826+options in the documentation of the `Servant.Utils.StaticFiles` module.
827+
824## Nested APIs
828## Nested APIs
825
829
826Let's see how you can define APIs in a modular way, while avoiding repetition.
830Let's see how you can define APIs in a modular way, while avoiding repetition.
servant-server/src/Servant/Utils/StaticFiles.hs+46−14
@@ -1,20 +1,27 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2−-- | This module defines a sever-side handler that lets you serve static files.
2+-- | This module defines server-side handlers that lets you serve static files.
3--
3--
4−-- - 'serveDirectory' lets you serve anything that lives under a particular
4+-- The most common needs for a web application are covered by
5−-- directory on your filesystem.
5+-- 'serveDirectoryWebApp`, but the other variants allow you to use
6+-- different `StaticSettings` and 'serveDirectoryWith' even allows you
7+-- to specify arbitrary 'StaticSettings' to be used for serving static files.
6−module Servant.Utils.StaticFiles (
8+module Servant.Utils.StaticFiles
7− serveDirectory,
9+ ( serveDirectoryWebApp
10+ , serveDirectoryWebAppLookup
11+ , serveDirectoryFileServer
12+ , serveDirectoryEmbedded
13+ , serveDirectoryWith
8− ) where
14+ ) where
9
15
16+import Data.ByteString (ByteString)
10−import Network.Wai.Application.Static (defaultFileServerSettings,
17+import Network.Wai.Application.Static
11− staticApp)
12import Servant.API.Raw (Raw)
18import Servant.API.Raw (Raw)
13import Servant.Server (Server)
19import Servant.Server (Server)
14import System.FilePath (addTrailingPathSeparator)
20import System.FilePath (addTrailingPathSeparator)
15#if !MIN_VERSION_wai_app_static(3,1,0)
21#if !MIN_VERSION_wai_app_static(3,1,0)
16import Filesystem.Path.CurrentOS (decodeString)
22import Filesystem.Path.CurrentOS (decodeString)
17#endif
23#endif
24+import WaiAppStatic.Storage.Filesystem (ETagLookup)
18
25
19-- | Serve anything under the specified directory as a 'Raw' endpoint.
26-- | Serve anything under the specified directory as a 'Raw' endpoint.
20--
27--
@@ -22,7 +29,7 @@ import Filesystem.Path.CurrentOS (decodeString)
22-- type MyApi = "static" :> Raw
29-- type MyApi = "static" :> Raw
23--
30--
24-- server :: Server MyApi
31-- server :: Server MyApi
25−-- server = serveDirectory "\/var\/www"
32+-- server = serveDirectoryWebApp "\/var\/www"
26-- @
33-- @
27--
34--
28-- would capture any request to @\/static\/\<something>@ and look for
35-- would capture any request to @\/static\/\<something>@ and look for
@@ -33,13 +40,38 @@ import Filesystem.Path.CurrentOS (decodeString)
33--
40--
34-- If your goal is to serve HTML, CSS and Javascript files that use the rest of the API
41-- If your goal is to serve HTML, CSS and Javascript files that use the rest of the API
35-- as a webapp backend, you will most likely not want the static files to be hidden
42-- as a webapp backend, you will most likely not want the static files to be hidden
36−-- behind a /\/static\// prefix. In that case, remember to put the 'serveDirectory'
43+-- behind a /\/static\// prefix. In that case, remember to put the 'serveDirectoryWebApp'
37-- handler in the last position, because /servant/ will try to match the handlers
44-- handler in the last position, because /servant/ will try to match the handlers
38-- in order.
45-- in order.
46+--
47+-- Corresponds to the `defaultWebAppSettings` `StaticSettings` value.
48+serveDirectoryWebApp :: FilePath -> Server Raw
49+serveDirectoryWebApp = staticApp . defaultWebAppSettings . fixPath
50+
51+-- | Same as 'serveDirectoryWebApp', but uses `defaultFileServerSettings`.
39−serveDirectory :: FilePath -> Server Raw
52+serveDirectoryFileServer :: FilePath -> Server Raw
40−serveDirectory =
53+serveDirectoryFileServer = staticApp . defaultFileServerSettings . fixPath
54+
55+-- | Same as 'serveDirectoryWebApp', but uses 'webAppSettingsWithLookup'.
56+serveDirectoryWebAppLookup :: ETagLookup -> FilePath -> Server Raw
57+serveDirectoryWebAppLookup etag =
58+ staticApp . flip webAppSettingsWithLookup etag . fixPath
59+
60+-- | Uses 'embeddedSettings'.
61+serveDirectoryEmbedded :: [(FilePath, ByteString)] -> Server Raw
62+serveDirectoryEmbedded files = staticApp (embeddedSettings files)
63+
64+-- | Alias for 'staticApp'. Lets you serve a directory
65+-- with arbitrary 'StaticSettings'. Useful when you want
66+-- particular settings not covered by the four other
67+-- variants. This is the most flexible method.
68+serveDirectoryWith :: StaticSettings -> Server Raw
69+serveDirectoryWith = staticApp
70+
71+fixPath :: FilePath -> FilePath
72+fixPath =
41#if MIN_VERSION_wai_app_static(3,1,0)
73#if MIN_VERSION_wai_app_static(3,1,0)
42− staticApp . defaultFileServerSettings . addTrailingPathSeparator
74+ addTrailingPathSeparator
43#else
75#else
44− staticApp . defaultFileServerSettings . decodeString . addTrailingPathSeparator
76+ decodeString . addTrailingPathSeparator
45#endif
77#endif