server: case insensitive lookup in session variable

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/3663
GitOrigin-RevId: b36666d8849a23dad209f9921f140390c2b57496
This commit is contained in:
paritosh-08 2022-02-24 18:37:32 +05:30 committed by hasura-bot
parent 6c2c46e94e
commit bc74046ab2
7 changed files with 132 additions and 8 deletions

View File

@ -5,6 +5,7 @@
### Bug fixes and improvements
(Add entries below in the order of server, console, cli, docs, others)
- server: add custom function for case insensitive lookup in session variable in request transformation
- server: Webhook Transforms can now delete request/response bodies explicitly.
- server: Fix truncation of session variables with variable length column types in MSSQL (#8158)
- server: improve baseline memory consumption for typical workloads

View File

@ -45,7 +45,7 @@ package graphql-engine
source-repository-package
type: git
location: https://github.com/hasura/kriti-lang.git
tag: 01930d88da1a95eee1e4d5e2a1ba78752548e599
tag: v0.3.1
source-repository-package
type: git

View File

@ -208,7 +208,7 @@ constraints: any.Cabal ==3.2.1.0,
jose -demos,
any.kan-extensions ==5.2.3,
any.keys ==3.12.3,
any.kriti-lang ==0.3.0,
any.kriti-lang ==0.3.1,
any.lens ==5.1,
lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy,
any.lens-aeson ==1.1.3,

View File

@ -2075,6 +2075,35 @@ RequestTransformation
- :ref:`TemplateEngine`
- Template language to be used for this transformation. Default: "Kriti"
.. note::
HGE provides the following functions that can be used in the template:
- ``not``: This function takes a boolean and returns its negation.
eg::
> {{not true}}
false
- ``escapeUri``: This function takes a string and escapes it as per URI specification.
eg::
> {{ escapeUri "?foo=bar/baz" }}
"%3Ffoo%3Dbar%2Fbaz"
- ``getSessionVariable``: This function takes a string and returns the session variable of the given name. This function can throw the following errors:
- Session variable {variable name} not found
- Session variable name should be a string
eg::
> {{getSessionVariable "myVariableName"}}
"myVariableValue"
.. _TransformHeaders:
TransformHeaders

View File

@ -37,9 +37,9 @@ import Data.Text.Encoding qualified as TE
import Data.Validation qualified as V
import Hasura.Incremental (Cacheable)
import Hasura.Prelude hiding (first)
import Hasura.Session (SessionVariables)
import Kriti (SerializedError (..), runKriti)
import Kriti.Error (serialize)
import Hasura.Session (SessionVariables, getSessionVariableValue, mkSessionVariable)
import Kriti (SerializedError (..), runKriti, runKritiWith)
import Kriti.Error (CustomFunctionError (..), serialize)
import Kriti.Parser (parser)
import Network.HTTP.Client.Transformable qualified as HTTP
import Network.URI qualified as URI
@ -73,7 +73,8 @@ data ReqTransformCtx = ReqTransformCtx
{ tcUrl :: Maybe J.Value,
tcBody :: J.Value,
tcSessionVars :: J.Value,
tcQueryParams :: Maybe J.Value
tcQueryParams :: Maybe J.Value,
tcFunctions :: M.HashMap T.Text (J.Value -> Either CustomFunctionError J.Value)
}
instance J.ToJSON ReqTransformCtx where
@ -441,7 +442,7 @@ mkReqTemplateTransform :: TemplatingEngine -> TemplateText -> ReqTransformCtx ->
mkReqTemplateTransform engine (TemplateText template) ReqTransformCtx {..} =
let context = [("$body", tcBody), ("$session_variables", tcSessionVars)] <> catMaybes [("$query_params",) <$> tcQueryParams, ("$base_url",) <$> tcUrl]
in case engine of
Kriti -> first (TransformErrorBundle . pure . J.toJSON . serialize) $ runKriti template context
Kriti -> first (TransformErrorBundle . pure . J.toJSON . serialize) $ runKritiWith (template) context tcFunctions
-- | Construct a Template Transformation function for Responses
mkRespTemplateTransform :: TemplatingEngine -> TemplateText -> RespTransformCtx -> Either TransformErrorBundle J.Value
@ -456,8 +457,19 @@ buildReqTransformCtx url sessionVars reqData =
{ tcUrl = Just $ J.toJSON url,
tcBody = fromMaybe J.Null $ J.decode @J.Value =<< view HTTP.body reqData,
tcSessionVars = J.toJSON sessionVars,
tcQueryParams = Just $ J.toJSON $ bimap TE.decodeUtf8 (fmap TE.decodeUtf8) <$> view HTTP.queryParams reqData
tcQueryParams = Just $ J.toJSON $ bimap TE.decodeUtf8 (fmap TE.decodeUtf8) <$> view HTTP.queryParams reqData,
tcFunctions = M.singleton "getSessionVariable" getSessionVar
}
where
getSessionVar :: J.Value -> Either CustomFunctionError J.Value
getSessionVar inp = case inp of
J.String txt ->
case sessionVarValue of
Just x -> Right $ J.String x
Nothing -> Left . CustomFunctionError $ "Session variable \"" <> txt <> "\" not found"
where
sessionVarValue = sessionVars >>= getSessionVariableValue (mkSessionVariable txt)
_ -> Left $ CustomFunctionError "Session variable name should be a string"
buildRespTransformCtx :: ReqTransformCtx -> BL.ByteString -> RespTransformCtx
buildRespTransformCtx reqCtx respBody =

View File

@ -0,0 +1,79 @@
- description: Test Webhook Transform getSessionVariable function | success
url: /v1/metadata
headers:
X-Hasura-Role: admin
status: 200
response:
body: some value
headers: []
method: GET
webhook_url: http://localhost:1234/
query:
type: test_webhook_transform
args:
webhook_url: http://localhost:1234
body:
hello: world
session_variables:
myVariable: some value
request_transform:
body: '{{ getSessionVariable "myVariable" }}'
template_engine: Kriti
- description: Test Webhook Transform getSessionVariable function | non existant session variable
url: /v1/metadata
headers:
X-Hasura-Role: admin
status: 200
response:
body:
- error_code: Function Error
source_position:
end_column: 51
start_line: 0
end_line: 0
start_column: 23
message: Session variable "this_variable_doesnt_exist" not found
headers: []
method: GET
webhook_url: http://localhost:1234/
query:
type: test_webhook_transform
args:
webhook_url: http://localhost:1234
body:
hello: world
session_variables:
myVariable: some value
request_transform:
body: '{{ getSessionVariable "this_variable_doesnt_exist" }}'
template_engine: Kriti
- description: Test Webhook Transform function | wrong function name
url: /v1/metadata
headers:
X-Hasura-Role: admin
status: 200
response:
body:
- error_code: Function Error
source_position:
end_column: 15
start_line: 0
end_line: 0
start_column: 4
message: Function fooFunction is not defined.
headers: []
method: GET
webhook_url: http://localhost:1234/
query:
type: test_webhook_transform
args:
webhook_url: http://localhost:1234
body:
hello: world
session_variables:
myVariable: some value
request_transform:
body: '{{ fooFunction "myVariable" }}'
template_engine: Kriti

View File

@ -238,6 +238,9 @@ class TestMetadata:
def test_webhook_transform_bad_eval(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/test_webhook_transform_bad_eval.yaml')
def test_webhook_transform_custom_functions(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/test_webhook_transform_custom_functions.yaml')
@pytest.mark.skipif(
os.getenv('HASURA_GRAPHQL_PG_SOURCE_URL_1') == os.getenv('HASURA_GRAPHQL_PG_SOURCE_URL_2') or
os.getenv('HASURA_GRAPHQL_PG_SOURCE_URL_1') is None or