servant-rawm (empty) → 0.1.0.0
raw patch · 15 files changed
+723/−0 lines, 15 filesdep +basedep +bytestringdep +filepathsetup-changed
Dependencies added: base, bytestring, filepath, http-client, http-media, http-types, resourcet, servant, servant-client, servant-docs, servant-rawm, servant-server, text, transformers, wai, wai-app-static, warp
Files
- CHANGELOG.md +4/−0
- LICENSE +30/−0
- README.md +10/−0
- Setup.hs +2/−0
- example/Api.hs +20/−0
- example/Client.hs +56/−0
- example/Server.hs +61/−0
- servant-rawm.cabal +138/−0
- src/Servant/RawM.hs +25/−0
- src/Servant/RawM/Internal.hs +23/−0
- src/Servant/RawM/Internal/API.hs +15/−0
- src/Servant/RawM/Internal/Client.hs +34/−0
- src/Servant/RawM/Internal/Docs.hs +150/−0
- src/Servant/RawM/Internal/Server.hs +114/−0
- stack.yaml +41/−0
+ CHANGELOG.md view
@@ -0,0 +1,4 @@++## 0.1.0.0++* Initial release.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Dennis Gosnell (c) 2017++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,10 @@++# Servant.RawM++[](http://travis-ci.org/cdepillabout/servant-rawm)+[](https://hackage.haskell.org/package/servant-rawm)+[](http://stackage.org/lts/package/servant-rawm)+[](http://stackage.org/nightly/package/servant-rawm)+++`servant-rawm` provides a way to embed a WAI `Application` in a Servant handler.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ example/Api.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeOperators #-}++module Api where++import Servant.API (Get, JSON, (:>), (:<|>))++import Servant.RawM (RawM)++type Api = OtherEndpoint1 :<|> RawEndpoint :<|> OtherEndpoint2++type OtherEndpoint1 = "other-endpoint-1" :> Get '[JSON] Int++type RawEndpoint = "serve-directory" :> RawM++type OtherEndpoint2 = "other-endpoint-2" :> Get '[JSON] Int++-- | The port to run the server on.+port :: Int+port = 8201
+ example/Client.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Data.ByteString.Lazy (ByteString)+import qualified Data.ByteString.Lazy as LBS+import Data.Monoid ((<>))+import Data.Proxy (Proxy(Proxy))+import Network.HTTP.Client (Response, defaultManagerSettings, newManager, responseBody)+import Network.HTTP.Media (MediaType)+import Network.HTTP.Types (Header, Method, methodGet)+import Servant.API ((:<|>)((:<|>)))+import Servant.Client+ (BaseUrl(BaseUrl), ClientEnv(ClientEnv), ClientM, Scheme(Http),+ client, runClientM)+import Servant.Common.Req (Req, appendToPath)++import Servant.RawM ()++import Api (Api, port)++-----------------------------------------+-- Clients generated by servant-client --+-----------------------------------------++-- We generate the client functions just like normal. Note that when we use+-- 'Throws' or 'NoThrow', the client functions get generated with the+-- 'Envelope' type.++otherEndpoint1 :: ClientM Int+getFile' :: Method -> (Req -> Req) -> ClientM (Int, ByteString, MediaType, [Header], Response ByteString)+otherEndpoint2 :: ClientM Int+otherEndpoint1 :<|> getFile' :<|> otherEndpoint2 = client (Proxy :: Proxy Api)++getFile :: String -> ClientM ByteString+getFile filePath = do+ (_, _, _, _, resp) <- getFile' methodGet $ \req -> appendToPath filePath req+ pure $ responseBody resp++----------+-- Main --+----------++main :: IO ()+main = do+ manager <- newManager defaultManagerSettings+ let clientEnv = ClientEnv manager baseUrl+ eitherRes <- runClientM (getFile "foo.txt") clientEnv+ case eitherRes of+ Left servantErr -> putStrLn $ "Got a ServantErr: " <> show servantErr+ Right fileContents -> do+ putStrLn "Successfully got file ./example/files/foo.txt:\n"+ LBS.putStr fileContents++baseUrl :: BaseUrl+baseUrl = BaseUrl Http "localhost" port ""
+ example/Server.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE TypeOperators #-}++module Main where++import Control.Monad.IO.Class (liftIO)+import Control.Monad.Trans.Reader (ReaderT, ask, runReaderT)+import Data.Monoid ((<>))+import Data.Proxy (Proxy(Proxy))+import Network.Wai (Application)+import Network.Wai.Handler.Warp (run)+import Servant (Handler, (:<|>)((:<|>)), Server, ServerT, serve)+import Servant.Utils.Enter ((:~>)(NT), enter)++import Servant.RawM (serveDirectoryWebApp)++import Api (Api, port)++data Config = Config+ { configInt1 :: Int+ , configInt2 :: Int+ , configDir :: FilePath+ } deriving Show++serverRoot :: ServerT Api (ReaderT Config IO)+serverRoot = getOtherEndpoint1 :<|> rawEndpoint :<|> getOtherEndpoint2++getOtherEndpoint1 :: ReaderT Config IO Int+getOtherEndpoint1 = do+ (Config int1 _ _) <- ask+ pure int1++rawEndpoint :: ReaderT Config IO Application+rawEndpoint = do+ (Config _ _ dir) <- ask+ serveDirectoryWebApp dir++getOtherEndpoint2 :: ReaderT Config IO Int+getOtherEndpoint2 = do+ (Config _ int2 _) <- ask+ pure int2++app :: Config -> Application+app conf = serve (Proxy :: Proxy Api) apiServer+ where+ apiServer :: Server Api+ apiServer = enter naturalTrans serverRoot++ naturalTrans :: ReaderT Config IO :~> Handler+ naturalTrans = NT transformation++ transformation :: ReaderT Config IO a -> Handler a+ transformation readerT = liftIO $ runReaderT readerT conf++config :: Config+config = Config {configInt1 = 3, configInt2 = 4, configDir = "./example/files"}++-- | Run the WAI 'Application' using 'run' on the port defined by 'port'.+main :: IO ()+main = do+ putStrLn $ "example RawM server running on port " <> show port+ run port $ app config
+ servant-rawm.cabal view
@@ -0,0 +1,138 @@+name: servant-rawm+version: 0.1.0.0+synopsis: Embed a raw 'Application' in a Servant API+description: Please see <https://github.com/cdepillabout/servant-rawm#readme README.md>.+homepage: https://github.com/cdepillabout/servant-rawm+license: BSD3+license-file: LICENSE+author: Dennis Gosnell+maintainer: cdep.illabout@gmail.com+copyright: 2017 Dennis Gosnell+category: Text+build-type: Simple+extra-source-files: CHANGELOG.md+ , README.md+ , stack.yaml+cabal-version: >=1.10++flag buildexample+ description: Build a small example program+ default: False++library+ hs-source-dirs: src+ exposed-modules: Servant.RawM+ , Servant.RawM.Internal+ , Servant.RawM.Internal.API+ , Servant.RawM.Internal.Client+ , Servant.RawM.Internal.Docs+ , Servant.RawM.Internal.Server+ build-depends: base >= 4.8 && < 5+ , bytestring >= 0.10+ , filepath >= 1.4+ , http-client >= 0.5+ , http-media >= 0.6+ , http-types >= 0.9+ , resourcet >= 1.0+ , servant >= 0.9+ , servant-client >= 0.9+ , servant-docs >= 0.9+ , servant-server >= 0.9+ , wai >= 3.2+ , wai-app-static >= 3.1+ default-language: Haskell2010+ ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -Wmissing-import-lists++ other-extensions: QuasiQuotes+ , TemplateHaskell++executable servant-rawm-example-client+ main-is: Client.hs+ other-modules: Api+ hs-source-dirs: example+ build-depends: base+ , bytestring+ , http-client+ , http-media+ , http-types+ , servant+ , servant-rawm+ , servant-client+ , text+ default-language: Haskell2010+ ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -Wmissing-import-lists -threaded -rtsopts -with-rtsopts=-N++ if flag(buildexample)+ buildable: True+ else+ buildable: False++-- executable servant-rawm-example-docs+-- main-is: Docs.hs+-- other-modules: Api+-- hs-source-dirs: example+-- build-depends: base+-- , aeson+-- , http-api-data+-- , servant+-- , servant-rawm+-- , servant-docs+-- , text+-- default-language: Haskell2010+-- ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -Wmissing-import-lists -threaded -rtsopts -with-rtsopts=-N++-- if flag(buildexample)+-- buildable: True+-- else+-- buildable: False++executable servant-rawm-example-server+ main-is: Server.hs+ other-modules: Api+ hs-source-dirs: example+ build-depends: base+ , servant+ , servant-rawm+ , servant-server+ , transformers+ , wai+ , warp+ default-language: Haskell2010+ ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -Wmissing-import-lists -threaded -rtsopts -with-rtsopts=-N++ if flag(buildexample)+ buildable: True+ else+ buildable: False++-- test-suite servant-rawm-doctest+-- type: exitcode-stdio-1.0+-- main-is: DocTest.hs+-- hs-source-dirs: test+-- build-depends: base+-- , doctest+-- , Glob+-- default-language: Haskell2010+-- ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N++-- test-suite servant-rawm-test+-- type: exitcode-stdio-1.0+-- main-is: Spec.hs+-- other-modules:+-- hs-source-dirs: test+-- build-depends: base+-- , bytestring+-- , hspec-wai+-- , tasty+-- , tasty-hspec+-- , tasty-hunit+-- , servant+-- , servant-rawm+-- , servant-server+-- , wai+-- default-language: Haskell2010+-- ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -Wmissing-import-lists++source-repository head+ type: git+ location: git@github.com:cdepillabout/servant-rawm.git
+ src/Servant/RawM.hs view
@@ -0,0 +1,25 @@+{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}++{- |+Module : Servant.RawM++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)++-}++module Servant.RawM+ (+ -- * 'RawM' API parameter+ RawM+ -- * Helper functions for writing simple file servers+ , serveDirectoryWebApp+ , serveDirectoryFileServer+ , serveDirectoryWebAppLookup+ , serveDirectoryEmbedded+ , serveDirectoryWith+ ) where++import Servant.RawM.Internal
+ src/Servant/RawM/Internal.hs view
@@ -0,0 +1,23 @@+{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}++{- |+Module : Servant.RawM.Internal++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++Export all of the instances for the Client, Docs, and Server.+-}++module Servant.RawM.Internal+ ( module X+ ) where++import Servant.RawM.Internal.API as X+import Servant.RawM.Internal.Client ()+import Servant.RawM.Internal.Docs ()+import Servant.RawM.Internal.Server as X
+ src/Servant/RawM/Internal/API.hs view
@@ -0,0 +1,15 @@+{- |+Module : Servant.RawM.Internal.API++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)++-}++module Servant.RawM.Internal.API where++import Data.Typeable (Typeable)++data RawM deriving Typeable
+ src/Servant/RawM/Internal/Client.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++{- |+Module : Servant.RawM.Internal.Client++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++This module only exports a 'HasClient' instance for 'RawM'.+-}++module Servant.RawM.Internal.Client where++import Data.ByteString.Lazy (ByteString)+import Data.Proxy (Proxy(Proxy))+import Network.HTTP.Client (Response)+import Network.HTTP.Media (MediaType)+import Network.HTTP.Types (Header, Method)+import Servant.Client (Client, ClientM, HasClient(clientWithRoute))+import Servant.Common.Req (Req, performRequest)++import Servant.RawM.Internal.API (RawM)++instance HasClient RawM where+ type Client RawM = Method -> (Req -> Req) -> ClientM (Int, ByteString, MediaType, [Header], Response ByteString)++ clientWithRoute :: Proxy RawM -> Req -> Client RawM+ clientWithRoute Proxy req method f = performRequest method $ f req
+ src/Servant/RawM/Internal/Docs.hs view
@@ -0,0 +1,150 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++{- |+Module : Servant.RawM.Internal.Docs++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++This module exports a 'HasDocs' instance for 'RawM'.+-}++module Servant.RawM.Internal.Docs where++-- import Data.Proxy (Proxy(Proxy))+-- import Data.ByteString.Lazy (ByteString)+-- import Data.Function ((&))+-- import Data.Monoid ((<>))+-- import Data.Text (Text)+-- import Network.HTTP.Media (MediaType)+-- import Servant.API (Verb, (:>))+-- import Servant.API.ContentTypes (AllMimeRender(allMimeRender))+-- import Servant.Docs+-- (Action, API, DocOptions, Endpoint, HasDocs(docsFor),+-- ToSample(toSamples))+-- import Servant.Docs.Internal (apiEndpoints, respBody, response)++-- import Servant.RawM.Internal.Envelope+-- (Envelope, toErrEnvelope, toSuccEnvelope)+-- import Servant.RawM.Internal.Prism ((<>~))+-- import Servant.RawM.Internal.Servant.API+-- (NoThrow, Throws, Throwing)+-- import Servant.RawM.Internal.Util (Snoc)++-- -- TODO: Make sure to also account for when headers are being used.++-- -- | Change a 'Throws' into 'Throwing'.+-- instance (HasDocs (Throwing '[e] :> api)) => HasDocs (Throws e :> api) where+-- docsFor+-- :: Proxy (Throws e :> api)+-- -> (Endpoint, Action)+-- -> DocOptions+-- -> API+-- docsFor Proxy = docsFor (Proxy :: Proxy (Throwing '[e] :> api))++-- -- | When @'Throwing' es@ comes before a 'Verb', generate the documentation for+-- -- the same 'Verb', but returning an @'Envelope' es@. Also add documentation+-- -- for the potential @es@.+-- instance+-- ( CreateRespBodiesFor es ctypes+-- , HasDocs (Verb method status ctypes (Envelope es a))+-- )+-- => HasDocs (Throwing es :> Verb method status ctypes a) where+-- docsFor+-- :: Proxy (Throwing es :> Verb method status ctypes a)+-- -> (Endpoint, Action)+-- -> DocOptions+-- -> API+-- docsFor Proxy (endpoint, action) docOpts =+-- let api =+-- docsFor+-- (Proxy :: Proxy (Verb method status ctypes (Envelope es a)))+-- (endpoint, action)+-- docOpts+-- in api & apiEndpoints . traverse . response . respBody <>~+-- createRespBodiesFor (Proxy :: Proxy es) (Proxy :: Proxy ctypes)++-- -- | When 'NoThrow' comes before a 'Verb', generate the documentation for+-- -- the same 'Verb', but returning an @'Envelope' \'[]@.+-- instance (HasDocs (Verb method status ctypes (Envelope '[] a)))+-- => HasDocs (NoThrow :> Verb method status ctypes a) where+-- docsFor+-- :: Proxy (NoThrow :> Verb method status ctypes a)+-- -> (Endpoint, Action)+-- -> DocOptions+-- -> API+-- docsFor Proxy (endpoint, action) docOpts =+-- docsFor+-- (Proxy :: Proxy (Verb method status ctypes (Envelope '[] a)))+-- (endpoint, action)+-- docOpts++-- -- | Create samples for a given @list@ of types, under given @ctypes@.+-- --+-- -- Additional instances of this class should not need to be created.+-- class CreateRespBodiesFor list ctypes where+-- createRespBodiesFor+-- :: Proxy list+-- -> Proxy ctypes+-- -> [(Text, MediaType, ByteString)]++-- -- | An empty list of types has no samples.+-- instance CreateRespBodiesFor '[] ctypes where+-- createRespBodiesFor+-- :: Proxy '[]+-- -> Proxy ctypes+-- -> [(Text, MediaType, ByteString)]+-- createRespBodiesFor Proxy Proxy = []++-- -- | Create a response body for each of the error types.+-- instance+-- ( AllMimeRender ctypes (Envelope '[e] ())+-- , CreateRespBodiesFor es ctypes+-- , ToSample e+-- )+-- => CreateRespBodiesFor (e ': es) ctypes where+-- createRespBodiesFor+-- :: Proxy (e ': es)+-- -> Proxy ctypes+-- -> [(Text, MediaType, ByteString)]+-- createRespBodiesFor Proxy ctypes =+-- createRespBodyFor (Proxy :: Proxy e) ctypes <>+-- createRespBodiesFor (Proxy :: Proxy es) ctypes++-- -- | Create a sample for a given @e@ under given @ctypes@.+-- createRespBodyFor+-- :: forall e ctypes.+-- (AllMimeRender ctypes (Envelope '[e] ()), ToSample e)+-- => Proxy e -> Proxy ctypes -> [(Text, MediaType, ByteString)]+-- createRespBodyFor Proxy ctypes = concatMap enc samples+-- where+-- samples :: [(Text, Envelope '[e] ())]+-- samples = fmap toErrEnvelope <$> toSamples (Proxy :: Proxy e)++-- enc :: (Text, Envelope '[e] ()) -> [(Text, MediaType, ByteString)]+-- enc (t, s) = uncurry (t,,) <$> allMimeRender ctypes s++-- -- | When a @'Throws' e@ comes immediately after a @'Throwing' es@, 'Snoc' the+-- -- @e@ onto the @es@.+-- instance (HasDocs (Throwing (Snoc es e) :> api)) =>+-- HasDocs (Throwing es :> Throws e :> api) where+-- docsFor+-- :: Proxy (Throwing es :> Throws e :> api)+-- -> (Endpoint, Action)+-- -> DocOptions+-- -> API+-- docsFor Proxy =+-- docsFor (Proxy :: Proxy (Throwing (Snoc es e) :> api))++-- -- | We can generate a sample of an @'Envelope' es a@ as long as there is a way+-- -- to generate a sample of the @a@.+-- --+-- -- This doesn't need to worry about generating a sample of @es@, because that is+-- -- taken care of in the 'HasDocs' instance for @'Throwing' es@.+-- instance ToSample a => ToSample (Envelope es a) where+-- toSamples :: Proxy (Envelope es a) -> [(Text, Envelope es a)]+-- toSamples Proxy = fmap toSuccEnvelope <$> toSamples (Proxy :: Proxy a)
+ src/Servant/RawM/Internal/Server.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++{- |+Module : Servant.RawM.Internal.Server++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++This module exports 'HasServer' instances for 'RawM', as well as some helper+functions for serving directories of files.+-}++module Servant.RawM.Internal.Server where++import Control.Monad.IO.Class (liftIO)+import Control.Monad.Trans.Resource (runResourceT)+import Data.ByteString (ByteString)+import Data.Proxy (Proxy(Proxy))+import Network.Wai+ (Application, Request, Response, ResponseReceived)+import Network.Wai.Application.Static+ (StaticSettings, defaultFileServerSettings, defaultWebAppSettings,+ embeddedSettings, staticApp, webAppSettingsWithLookup)+import Servant (Context, HasServer(route), Handler, ServerT, runHandler)+import Servant.Server.Internal+ (Delayed, Router'(RawRouter), RouteResult(Fail, FailFatal, Route), responseServantErr,+ runDelayed)+import System.FilePath (addTrailingPathSeparator)+import WaiAppStatic.Storage.Filesystem (ETagLookup)++import Servant.RawM.Internal.API (RawM)++instance HasServer RawM context where+ type ServerT RawM m = m Application+ route+ :: forall env.+ Proxy RawM+ -> Context context+ -> Delayed env (Handler Application)+ -> Router' env (Request -> (RouteResult Response -> IO ResponseReceived) -> IO ResponseReceived)+ route Proxy _ rawApplication = RawRouter go+ where+ go+ :: env+ -> Request+ -> (RouteResult Response -> IO ResponseReceived)+ -> IO ResponseReceived+ go env request respond =+ runResourceT $ do+ routeRes <- runDelayed rawApplication env request+ liftIO $+ case routeRes of+ (Fail e) -> respond $ Fail e+ (FailFatal e) -> respond $ FailFatal e+ (Route handlerApp) -> do+ eitherApp <- runHandler handlerApp+ case eitherApp of+ Left err -> respond . Route $ responseServantErr err+ Right app -> app request (respond . Route)+++-- | Serve anything under the specified directory as a 'RawM' endpoint.+--+-- @+-- type MyApi = "static" :> RawM+--+-- server :: ServerT MyApi m+-- 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 :: Applicative m => FilePath -> ServerT RawM m+serveDirectoryWebApp = serveDirectoryWith . defaultWebAppSettings . addTrailingPathSeparator++-- | Same as 'serveDirectoryWebApp', but uses `defaultFileServerSettings`.+serveDirectoryFileServer :: Applicative m => FilePath -> ServerT RawM m+serveDirectoryFileServer = serveDirectoryWith . defaultFileServerSettings . addTrailingPathSeparator++-- | Same as 'serveDirectoryWebApp', but uses 'webAppSettingsWithLookup'.+serveDirectoryWebAppLookup :: Applicative m => ETagLookup -> FilePath -> ServerT RawM m+serveDirectoryWebAppLookup etag =+ serveDirectoryWith . flip webAppSettingsWithLookup etag . addTrailingPathSeparator++-- | Uses 'embeddedSettings'.+serveDirectoryEmbedded :: Applicative m => [(FilePath, ByteString)] -> ServerT RawM 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 :: Applicative m => StaticSettings -> ServerT RawM m+serveDirectoryWith = pure . staticApp
+ stack.yaml view
@@ -0,0 +1,41 @@+# For more information, see: http://docs.haskellstack.org/en/stable/yaml_configuration.html++# Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2)+resolver: lts-9.2++# Local packages, usually specified by relative directory name+packages:+- '.'++# Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3)+extra-deps: []++# Override default flag values for local packages and extra-deps+flags: {}++# Extra package databases containing global packages+extra-package-dbs: []++# Control whether we use the GHC we find on the path+# system-ghc: true++# Require a specific version of stack, using version ranges+# require-stack-version: -any # Default+# require-stack-version: >= 1.0.0++# Override the architecture used by stack, especially useful on Windows+# arch: i386+# arch: x86_64++# Extra directories used by stack for building+# extra-include-dirs: [/path/to/dir]+# extra-lib-dirs: [/path/to/dir]++# Allow a newer minor version of GHC than the snapshot specifies+# compiler-check: newer-minor++# Enable Hackage-friendly mode, for more details see+# https://docs.haskellstack.org/en/stable/yaml_configuration/#pvp-bounds+# This has been disabled because of the following exchange:+# https://github.com/cdepillabout/pretty-simple/pull/1#issuecomment-272706215+#pvp-bounds: both