cdepillabout/servant-static-th

Type-safe links?

Closed this issue · 3 comments

Is there a recommended way of generating type-safe links for a directory who's API has been created by createApiAndServerDecs?

Servant has some functionality for generating type-safe links: https://hackage.haskell.org/package/servant-0.17/docs/Servant-Links.html.

I'm going to go ahead and close this, since I don't think that there is anything this library can do in particular about this.

If this doesn't work for you, and you think there would be a nice way to handle it in this library, please feel free to respond here and re-open this issue.

I'm going to go ahead and close this, since I don't think that there is anything this library can do in particular about this.

This library generates servant routes using the following approach, right:

type Api = 
  "assets" :> 
    ("js" :> 
      ( "main.js :> Get ...) :<|>
      ( "app.js :> Get ...) :<|>
      ( "something.js :> Get ...))

This makes it almost impossible to generate type-safe links, because:

  • without using records for generating routes, the only way to do this is to do something like:

     link1 :<|> link2 :<|> link3 = allLinks (Proxy :: Proxy Api)
    
  • and for the above to work, you need to know beforehand, which static file is in which position in the routes.

Is there any way around this, that I'm missing?

@saurabhnanda Here's an example of doing this, using the example here:

diff --git a/example/Example.hs b/example/Example.hs
index 13729c2..abd0b7f 100644
--- a/example/Example.hs
+++ b/example/Example.hs
@@ -1,13 +1,15 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeOperators #-}
 
 module Main where
 
 import Data.Proxy (Proxy(Proxy))
+import Data.Text (Text)
 import Network.Wai (Application)
 import Network.Wai.Handler.Warp (run)
-import Servant.Server (serve)
-import Servant.Static.TH (createApiAndServerDecs)
+import Servant
+import Servant.Static.TH
 
 -- 'createApiAndServerDecs' will use the files in the directory @example/example-dir@
 -- to create two things.
@@ -66,3 +68,8 @@ app = serve (Proxy :: Proxy FrontEndApi) frontEndServer
 
 main :: IO ()
 main = run 8080 app
+
+hello :: Text
+hello =
+  let p = Proxy :: Proxy ("dir" :> "inner-file.html" :> Get '[HTML] Html)
+  in toUrlPiece (safeLink (Proxy :: Proxy FrontEndApi) p :: Link)
diff --git a/servant-static-th.cabal b/servant-static-th.cabal
index 18e9051..63528e5 100644
--- a/servant-static-th.cabal
+++ b/servant-static-th.cabal
@@ -54,6 +54,7 @@ executable servant-static-th-example
   build-depends:       base
                      , servant-server
                      , servant-static-th
+                     , text
                      , wai
                      , warp
   default-language:    Haskell2010

These changes are on the current master (commit 3baf38a).

I tested building this with the command stack build --flag servant-static-th:buildexample.

The actual example is here:

hello :: Text
hello =
  let p = Proxy :: Proxy ("dir" :> "inner-file.html" :> Get '[HTML] Html)
  in toUrlPiece (safeLink (Proxy :: Proxy FrontEndApi) p :: Link)

Does this help?


Maybe you're looking for type-safe links like Yesod generates? Maybe something like the following:

dir_inner_file_html_get_html_html :: Proxy ("dir" :> "inner-file.html" :> Get '[HTML] Html)
dir_inner_file_html_get_html_html = Proxy

I don't remember exactly how Yesod generates these type-safe files, but I think it is something like this.

servant-static-th doesn't generate anything like this, but it could if someone is interested in adding it.

If you (or anyone else) is interesting in seeing this, please let me know.