0

I have the following web server:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes       #-}
{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE TypeFamilies      #-}
import           Data.Text        (Text)
import           Yesod

data App = App

mkYesod "App" [parseRoutes|
/      HomeR  GET
/link1 Link1R GET
/link2 Link2R GET
/link3 Link3R GET
/link4 Link4R GET
|]

instance Yesod App where

getHomeR :: Handler Html
getHomeR = defaultLayout $ do
    setTitle "Redirects"
    [whamlet|
        <p>
            <a href=@{Link1R}>Click to start the redirect chain!
    |]

getLink1R, getLink2R, getLink3R :: Handler ()
getLink1R = redirect Link2R -- /link2
getLink2R = redirect (Link3R, [("foo", "bar")]) -- /link3?foo=bar
getLink3R = redirect $ Link4R :#: ("baz" :: Text) -- /link4#baz

getLink4R :: Handler Html
getLink4R = defaultLayout
    [whamlet|
        <p>You made it!
    |]

main :: IO ()
main = warp 3000 App

But I have route prefix that's from somewhere such as environment variable:

/prefix/      HomeR  GET
/prefix/link1 Link1R GET
/prefix/link2 Link2R GET
/prefix/link3 Link3R GET
/prefix/link4 Link4R GET

How do I achieve it?

I tried approot but it doesn't seem to work...

stevemao
  • 1,423
  • 1
  • 16
  • 29
  • I'm not entirely sure if I understand what the pproblem is. What is not working? – Willem Van Onsem Jan 27 '20 at 11:37
  • The url prefix is coming from a setting or environment variable. I'm not sure what's the best way to do it. – stevemao Jan 27 '20 at 11:42
  • 2
    Is it supposed to be a variable at _compile time_ or _runtime_? If the latter, then Template Haskell can't possibly be used for it. – leftaroundabout Jan 27 '20 at 11:42
  • Both can be an option. For learning purposes what's the best way for both? I'm quite new to functional programming :) Thanks a lot! – stevemao Jan 27 '20 at 11:44
  • I think compile time would be better but I'd like to learn both solutions. – stevemao Jan 27 '20 at 11:53
  • Well, again, for runtime this can't be a question about TH but rather about Yesod. There's a very simple hack solution if you can make the variable part a _postfix_ rather than prefix. But I think it would make sense to focus the question on the compile-time version, if you want to learn about Haskell rather than Yesod specifics. – leftaroundabout Jan 27 '20 at 12:10
  • The runtime solution doesn't have to be about TH. About Yesod is fine. Build time solution doesn't have to be related to TH too and whatever is the best practice in Haskell. I can't make the path postfix but I'm interested to know what you mean by hack. – stevemao Jan 27 '20 at 12:14

1 Answers1

0

I'm using cleanPath to drop the prefix:

    cleanPath app s =
        if corrected == s
            then Right $ dropPrefix $ map dropDash s
            else Left corrected
      where
        corrected = filter (not . T.null) s
        dropDash t
            | T.all (== '-') t = T.drop 1 t
            | otherwise = t
        dropPrefix s' = case routePrefix $ appSettings app of
            Nothing -> s'
            Just prefix -> case headMay s' of
                            Just t -> if t == prefix then drop 1 s' else ["wrong prefix"]
                            Nothing -> ["wrong prefix"]

If you know a better way of doing it please comment or add an answer. Thanks!

stevemao
  • 1,423
  • 1
  • 16
  • 29