Files
graphql-engine/server/src-lib/Data/URL/Template.hs
Karthikeyan Chinnakonda a26bc80496 accept a new argument claims_namespace_path in JWT config (#4365)
* add new optional field `claims_namespace_path` in JWT config

* return value when empty array is found in executeJSONPath

* update the docs related to claims_namespace_path

* improve encodeJSONPath, add property tests for parseJSONPath

* throw error if both claims_namespace_path and claims_namespace are set

* refactor the Data.Parser.JsonPath to Data.Parser.JSONPathSpec

* update the JWT docs

Co-Authored-By: Marion Schleifer <marion@hasura.io>

Co-authored-by: Marion Schleifer <marion@hasura.io>
Co-authored-by: rakeshkky <12475069+rakeshkky@users.noreply.github.com>
Co-authored-by: Tirumarai Selvan <tirumarai.selvan@gmail.com>
2020-04-16 12:15:21 +05:30

95 lines
3.0 KiB
Haskell

-- | A simple URL templating that enables interpolating environment variables
module Data.URL.Template
( URLTemplate
, TemplateItem
, Variable
, printURLTemplate
, parseURLTemplate
, renderURLTemplate
, genURLTemplate
)
where
import Hasura.Prelude
import qualified Data.Text as T
import Data.Attoparsec.Combinator (lookAhead)
import Data.Attoparsec.Text
import Instances.TH.Lift ()
import Language.Haskell.TH.Syntax (Lift)
import System.Environment (lookupEnv)
import Test.QuickCheck
newtype Variable = Variable {unVariable :: Text}
deriving (Show, Eq, Lift, Generic)
printVariable :: Variable -> Text
printVariable var = "{{" <> unVariable var <> "}}"
data TemplateItem
= TIText !Text
| TIVariable !Variable
deriving (Show, Eq, Lift, Generic)
printTemplateItem :: TemplateItem -> Text
printTemplateItem = \case
TIText t -> t
TIVariable v -> printVariable v
-- | A String with environment variables enclosed in '{{' and '}}'
-- http://{{APP_HOST}}:{{APP_PORT}}/v1/api
newtype URLTemplate = URLTemplate {unURLTemplate :: [TemplateItem]}
deriving (Show, Eq, Lift, Generic)
printURLTemplate :: URLTemplate -> Text
printURLTemplate = T.concat . map printTemplateItem . unURLTemplate
parseURLTemplate :: Text -> Either String URLTemplate
parseURLTemplate t = parseOnly parseTemplate t
where
parseTemplate :: Parser URLTemplate
parseTemplate = do
items <- many parseTemplateItem
lastItem <- TIText <$> takeText
pure $ URLTemplate $ items <> [lastItem]
parseTemplateItem :: Parser TemplateItem
parseTemplateItem =
(TIVariable <$> parseVariable)
<|> (TIText . T.pack <$> manyTill anyChar (lookAhead $ string "{{"))
parseVariable :: Parser Variable
parseVariable =
string "{{" *> (Variable . T.pack <$> manyTill anyChar (string "}}"))
renderURLTemplate :: MonadIO m => URLTemplate -> m (Either String Text)
renderURLTemplate template = do
eitherResults <- mapM renderTemplateItem $ unURLTemplate template
let errorVariables = lefts eitherResults
pure $ case errorVariables of
[] -> Right $ T.concat $ rights eitherResults
_ -> Left $ T.unpack $ "Value for environment variables not found: "
<> T.intercalate ", " errorVariables
where
renderTemplateItem = \case
TIText t -> pure $ Right t
TIVariable (Variable var) -> do
maybeEnvValue <- liftIO $ lookupEnv $ T.unpack var
pure $ case maybeEnvValue of
Nothing -> Left var
Just value -> Right $ T.pack value
-- QuickCheck generators
instance Arbitrary Variable where
arbitrary = Variable . T.pack <$> listOf1 (elements $ alphaNumerics <> " -_")
instance Arbitrary URLTemplate where
arbitrary = URLTemplate <$> listOf (oneof [genText, genVariable])
where
genText = (TIText . T.pack) <$> listOf1 (elements $ alphaNumerics <> " ://")
genVariable = TIVariable <$> arbitrary
genURLTemplate :: Gen URLTemplate
genURLTemplate = arbitrary