Skip to content

Instantly share code, notes, and snippets.

@kwannoel
Created May 31, 2021 07:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kwannoel/d303f548bc6e65ddf83e2bc33e7fc5a7 to your computer and use it in GitHub Desktop.
Save kwannoel/d303f548bc6e65ddf83e2bc33e7fc5a7 to your computer and use it in GitHub Desktop.
Parse routes
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
import Control.Arrow((>>>), (&&&))
import Data.Maybe (catMaybes)
import qualified Data.Text as T
import Data.Text (Text)
import Data.List.NonEmpty (NonEmpty, nonEmpty)
data ApiRoute = ApiRoute { method :: Method, path :: Path } deriving Show
data Method = LIST | POST deriving Show
type Path = NonEmpty PathFrag
type PathFrag = Text
parse :: Text -> Maybe ApiRoute
parse = T.words >>> (methodP &&& pathsP)
>>> \case (Just method, Just path) -> Just ApiRoute{..}
_ -> Nothing
where
methodP ("LIST":_) = Just LIST
methodP ("POST":_) = Just POST
methodP _ = Nothing
pathsP (_:[paths]) = nonEmpty . dropWhile (== "") . T.split (== '/') $ paths
pathsP _ = Nothing
{-# LANGUAGE RecordWildCards #-}
import qualified Text.Parsec as P
import Text.Parsec (Parsec, ParseError, (<|>), runP)
import Data.Functor ((<&>), ($>))
data ApiRoute = ApiRoute { method :: Method, path :: Path } deriving Show
data Method = LIST | POST deriving Show
type Path = [PathFrag]
data PathFrag = Static String | Capture String deriving Show
type ParseResult = Either ParseError ApiRoute
parse :: String -> ParseResult
parse = runP apiRouteP () ""
where
apiRouteP = do
method <- methodP
_ <- P.spaces
path <- pathP
return $ ApiRoute{..}
where
methodP = (P.string "LIST" $> LIST) <|> (P.string "POST" $> POST)
pathP = P.many1 $ P.char '/' *> pathFragP
where
pathFragP = (letters >>= return . Static)
<|> (leftCurlyBrace *> letters <* rightCurlyBrace <&> Capture)
letters = P.many1 P.letter
leftCurlyBrace = P.char '{'
rightCurlyBrace = P.char '}'
rightToMaybe = either (const Nothing) Just
------------
-- Testcases
------------
-- LIST /domains/{domain}/info
-- Just (ApiRoute {method = LIST, path = [Static "domains",Capture "domain",Static "info"]})
-- POST /domains/{domain}/users
-- Just (ApiRoute {method = POST, path = [Static "domains",Capture "domain",Static "users"]})
-- Note: Not all METHODS are currently parsed e.g. GET, PUT ...
-- Not all PATHS are currently parsed e.g. '/'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment