catch all for static files ?

8 views
Skip to first unread message

Andreas Reuleaux

unread,
Aug 10, 2018, 10:44:27 PM8/10/18
to haskell-servant
Hi,

I can successfully server static files, e.g. in directorty static, as in

<link href="./static/main.css" media="screen" type="text/css" rel="stylesheet" />

with

type API = ...
:<|> "static" :> Raw


api :: Proxy API
api = Proxy


srv :: Server API
srv = ...
:<|> (serveDirectoryFileServer "static")



Now I wonder, if it would be possible to serve

<link href="./main.css" media="screen" type="text/css" rel="stylesheet" />


as well, with some kind of catch all rule (not working, but you get the idea, hopefully):



type API = ...
:<|> "." :> Raw


api :: Proxy API
api = Proxy


srv :: Server API
srv = ...
:<|> (serveDirectoryFileServer ".")



Is that possible ? Thanks.

- Andreas


Alp Mestanogullari

unread,
Aug 11, 2018, 3:27:00 PM8/11/18
to r...@a-rx.info, haskell-servant
By "as well", do you mean that you would like to serve the actual main.css file under both /main.css and /static/main.css, something along those lines? 

--
You received this message because you are subscribed to the Google Groups "haskell-servant" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-serva...@googlegroups.com.
To post to this group, send email to haskell...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/haskell-servant/87tvo1d3lp.fsf%40a-rx.info.
For more options, visit https://groups.google.com/d/optout.


--
Alp Mestanogullari

Andreas Reuleaux

unread,
Aug 11, 2018, 6:24:39 PM8/11/18
to haskell-servant
Well, thanks for getting back to me.

I have just very few static files (for the purpose of this
discussion, say just one: main.css), and would like to serve
them, without having to put them in a directory static,
from my current directory ie.

I would then reference "main.css" with

<link href="./main.css" media="screen" type="text/css" rel="stylesheet" />

for example, not with

<link href="./static/main.css" media="screen" type="text/css" rel="stylesheet" />

Thus you may read my question as: "serve a single static file from the current
directory?". - If I have more than one static file to serve (say three), then
it doesn't really matter to me, if I have three lines of code to add (pseudo code):

serve file1.css
serve file2.pdf
serve file3.txt

or (preferrably) just one line to add: serve current directory

serve "."

I do not want to get into a discussion, whether it's a good idea to do so, or not
(I can well see the advantage of having a directory "static" for a production system),
I just want the system to behave my preferred way (...href="./main.css"), not the other
way around: having to adapt to the system's limitations (...href="./static/main.css").

For what it's worth: I have meanwhile found a solution, albeit terribly
complicated (see below), thus I wonder if there is simpler way:

Thanks again,
Andreas

--------------------

import GHC.Generics
import Network.HTTP.Media ((//))
import Network.Wai.Handler.Warp
import Servant
import Data.Typeable (Typeable)
import qualified Data.ByteString.Lazy as L
import Network.HTTP.Media ((/:))


data Css deriving Typeable

instance Accept Css where
contentType _ = "text" // "css" /: ("charset", "utf-8")

newtype RawFile = RawFile { unRawFile :: L.ByteString }


instance MimeRender Css RawFile where
mimeRender _ = unRawFile


-- It can be anywhere in your API except the last line.
type API = ...
:<|> "main.css" :> Get '[Css] RawFile


api :: Proxy API
api = Proxy


-- srv :: Handler RawHtml
srv :: Server API
srv
= ...
:<|> ( fmap RawFile (liftIO $ do L.readFile "/home/rx/work/site/main.css" ) )

Alp Mestanogullari

unread,
Aug 12, 2018, 3:27:03 PM8/12/18
to Andreas Reuleaux, haskell-servant
Well, one option would be to just have

type API = ... :<|> Raw
server = ... :<|> serveDirectory "."

but this may expose files that are not meant to be served.

Another reasonable option is the one you came up with. Somewhere in between you'd have a close cousin of serveDirectory that would just serve a given list of files and nothing else. You'd have to implement it but just once.

Finally, I think I have seen a servant-static-th package that uses TH to embed static files to be served directly into the executable. This may or may not be a satisfactory solution for youbut it certainly is relevant.

I think this is all my brain has in store for your problem at the moment.

Andreas Reuleaux

unread,
Aug 12, 2018, 8:18:06 PM8/12/18
to haskell-servant
Alp Mestanogullari <alpm...@gmail.com> writes:

> Well, one option would be to just have
>
> type API = ... :<|> Raw
> server = ... :<|> serveDirectory "."
>
> but this may expose files that are not meant to be served.


Ah, OK, I see: just

type API = ... :<|> Raw
server = ... :<|> serveDirectory "."

I thought, I had tried that before, with no luck but now
I can see that it is working fine - my bad.

Thanks a lot. I will try your other suggestions in the next days
as time permits.

-A
Reply all
Reply to author
Forward
0 new messages