2022-03-23 23:23:46 +03:00
|
|
|
module Hasura.RQL.WebhookTransformsSpec
|
|
|
|
( spec,
|
|
|
|
)
|
|
|
|
where
|
2021-09-16 14:03:01 +03:00
|
|
|
|
2022-03-23 23:23:46 +03:00
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
import Data.Aeson (FromJSON, ToJSON, eitherDecode, encode, fromJSON, toJSON)
|
2021-09-16 14:03:01 +03:00
|
|
|
import Data.CaseInsensitive qualified as CI
|
2021-09-29 11:13:30 +03:00
|
|
|
import Data.List (nubBy)
|
2021-09-16 14:03:01 +03:00
|
|
|
import Data.Set qualified as S
|
|
|
|
import Hasura.Prelude
|
2022-03-23 23:23:46 +03:00
|
|
|
import Hasura.RQL.DDL.Webhook.Transform (RequestFields (..), RequestTransformFns, WithOptional (..), withOptional)
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Body (BodyTransformFn)
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Body qualified as Body
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Class (Template (..), TemplatingEngine (..), UnescapedTemplate (..))
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Headers (HeadersTransformFn, TransformFn (..))
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Headers qualified as Headers
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Method (Method (..), MethodTransformFn)
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Method qualified as Method
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.QueryParams (QueryParamsTransformFn, TransformFn (..))
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.QueryParams qualified as QueryParams
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Url (UrlTransformFn)
|
|
|
|
import Hasura.RQL.DDL.Webhook.Transform.Url qualified as Url
|
|
|
|
import Hedgehog (Gen, MonadTest, forAll, tripping, (===))
|
2021-09-16 14:03:01 +03:00
|
|
|
import Hedgehog.Gen qualified as Gen
|
|
|
|
import Hedgehog.Range qualified as Range
|
2022-03-23 23:23:46 +03:00
|
|
|
import Test.Hspec (Spec, describe, it)
|
|
|
|
import Test.Hspec.Hedgehog (hedgehog)
|
|
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
2021-09-16 14:03:01 +03:00
|
|
|
|
|
|
|
spec :: Spec
|
2022-03-23 23:23:46 +03:00
|
|
|
spec = describe "WebhookTransform" do
|
|
|
|
it "Method RoundTrip" . hedgehog $
|
|
|
|
forAll genMethod >>= trippingJSON
|
|
|
|
|
|
|
|
it "StringTemplateText RoundTrip" . hedgehog $
|
|
|
|
forAll genUnescapedTemplate >>= trippingJSON
|
|
|
|
|
|
|
|
it "Url RoundTrip" . hedgehog $
|
|
|
|
forAll genUrl >>= trippingJSON
|
|
|
|
|
|
|
|
it "Template RoundTrip" . hedgehog $
|
|
|
|
forAll genTemplate >>= trippingJSON
|
|
|
|
|
|
|
|
it "TemplateEngine RoundTrip" . hedgehog $
|
|
|
|
forAll genTemplatingEngine >>= trippingJSON
|
|
|
|
|
|
|
|
it "TransformHeaders" . hedgehog $ do
|
|
|
|
headers <- forAll genTransformHeaders
|
|
|
|
let sortH (Headers.AddReplaceOrRemoveFields {..}) =
|
|
|
|
Headers.AddReplaceOrRemoveFields (sort addOrReplaceHeaders) (sort removeHeaders)
|
|
|
|
let headersMaybe = eitherDecode $ encode headers
|
|
|
|
Right (sortH headers) === fmap sortH headersMaybe
|
|
|
|
|
|
|
|
it "MetadataRequestTransform RoundTrip" . hedgehog $ do
|
|
|
|
reqFields <- forAll genRequestTransformDefunc
|
|
|
|
let sortH (WithOptional Nothing) = WithOptional Nothing
|
|
|
|
sortH
|
|
|
|
(WithOptional (Just (HeadersTransformFn_ (Headers.AddReplaceOrRemove (Headers.AddReplaceOrRemoveFields {..}))))) =
|
|
|
|
WithOptional . Just . HeadersTransformFn_ . Headers.AddReplaceOrRemove $
|
|
|
|
Headers.AddReplaceOrRemoveFields (sort addOrReplaceHeaders) (sort removeHeaders)
|
|
|
|
|
|
|
|
let sortQ (WithOptional Nothing) = WithOptional Nothing
|
|
|
|
sortQ
|
|
|
|
(WithOptional (Just (QueryParamsTransformFn_ (QueryParams.AddOrReplace qs)))) =
|
|
|
|
WithOptional . Just . QueryParamsTransformFn_ . QueryParams.AddOrReplace $
|
|
|
|
sortOn fst qs
|
server: use kriti template to generate query param from list
## Description ✍️
This PR adds support to generate query params directly using a kriti template which can be used to flatten a list of parameter arguments as well.
### Changes in the Metadata API
Earlier the `query_params` key inside `request_transform` used to take in an object of key/value pairs where the `key` represents the query parameter name and `value` points to the value of the parameter or a kriti template which could be resolved to the value.
With this PR, we provide the user with more freedom to generate the complete query string using kriti template. The `query_params` can now take in a string as well which will be a kriti template. This new change needs to be incorporated on the console and CLI metadata import/export as well.
- [x] CLI: Compatible, no changes required
- [ ] Console
## Changelog ✍️
__Component__ : server
__Type__: feature
__Product__: community-edition
### Short Changelog
use kriti template to generate query param from list of arguments
### Related Issues ✍
https://hasurahq.atlassian.net/browse/GS-243
### Solution and Design ✍
We use a kriti template to generate the complete query parameter string.
| Query Template | Output |
|---|---|
| `{{ concat ([concat({{ range _, x := [\"apple\", \"banana\"] }} \"tags={{x}}&\" {{ end }}), \"flag=smthng\"]) }}`| `tags=apple&tags=banana&flag=smthng` |
| `{{ concat ([\"tags=\", concat({{ range _, x := $body.input }} \"{{x}},\" {{ end }})]) }}` | `tags=apple%2Cbanana%2C` |
### Steps to test and verify ✍
- start HGE and make the following request to `http://localhost:8080/v1/metadata`:
```json
{
"type": "test_webhook_transform",
"args": {
"webhook_url": "http://localhost:3000",
"body": {
"action": {
"name": "actionName"
},
"input": ["apple", "banana"]
},
"request_transform": {
"version": 2,
"url": "{{$base_url}}",
"query_params": "{{ concat ([concat({{ range _, x := $body.input }} \"tags={{x}}&\" {{ end }}), \"flag=smthng\"]) }}",
"template_engine": "Kriti"
}
}
}
```
- you should receive the following as output:
```json
{
"body": {
"action": {
"name": "actionName"
},
"input": [
"apple",
"banana"
]
},
"headers": [],
"method": "GET",
"webhook_url": "http://localhost:3000?tags=apple&tags=banana&flag=smthng"
}
```
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6961
Co-authored-by: Tirumarai Selvan <8663570+tirumaraiselvan@users.noreply.github.com>
GitOrigin-RevId: 712ba038f03009edc3e8eb0435e723304943399a
2022-11-29 23:26:04 +03:00
|
|
|
sortQ
|
|
|
|
(WithOptional (Just (QueryParamsTransformFn_ (QueryParams.ParamTemplate qs)))) =
|
|
|
|
WithOptional . Just . QueryParamsTransformFn_ . QueryParams.ParamTemplate $ qs
|
2022-03-23 23:23:46 +03:00
|
|
|
let sortRF rf@RequestFields {requestHeaders, queryParams} =
|
|
|
|
rf {requestHeaders = sortH requestHeaders, queryParams = sortQ queryParams}
|
|
|
|
let reqFieldsMaybe = eitherDecode $ encode reqFields
|
|
|
|
Right (sortRF reqFields) === fmap sortRF reqFieldsMaybe
|
|
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- Generators
|
2021-09-16 14:03:01 +03:00
|
|
|
|
2022-03-08 03:42:06 +03:00
|
|
|
genMethod :: Gen Method
|
|
|
|
genMethod = (Method . CI.mk) <$> Gen.text (Range.constant 3 20) Gen.alphaNum
|
|
|
|
|
2021-09-16 14:03:01 +03:00
|
|
|
genTemplatingEngine :: Gen TemplatingEngine
|
2022-03-23 23:23:46 +03:00
|
|
|
genTemplatingEngine = Gen.enumBounded
|
2021-09-16 14:03:01 +03:00
|
|
|
|
|
|
|
-- NOTE: This generator is strictly useful for roundtrip aeson testing
|
|
|
|
-- and does not produce valid template snippets.
|
2022-03-08 03:42:06 +03:00
|
|
|
genTemplate :: Gen Template
|
|
|
|
genTemplate = Template . wrap <$> Gen.text (Range.constant 3 20) Gen.alphaNum
|
2021-09-29 11:13:30 +03:00
|
|
|
where
|
|
|
|
wrap txt = "\"" <> txt <> "\""
|
2021-09-16 14:03:01 +03:00
|
|
|
|
2022-03-08 03:42:06 +03:00
|
|
|
genUnescapedTemplate :: Gen UnescapedTemplate
|
|
|
|
genUnescapedTemplate = UnescapedTemplate <$> Gen.text (Range.constant 3 20) Gen.alphaNum
|
2022-01-19 07:46:42 +03:00
|
|
|
|
2022-03-23 23:23:46 +03:00
|
|
|
genTransformHeaders :: Gen Headers.AddReplaceOrRemoveFields
|
2021-09-16 14:03:01 +03:00
|
|
|
genTransformHeaders = do
|
|
|
|
numHeaders <- Gen.integral $ Range.constant 1 20
|
|
|
|
|
|
|
|
let genHeaderKey = CI.mk <$> Gen.text (Range.constant 1 20) Gen.alphaNum
|
2022-03-08 03:42:06 +03:00
|
|
|
genHeaderValue = genUnescapedTemplate
|
2021-09-16 14:03:01 +03:00
|
|
|
|
|
|
|
genKeys = S.toList <$> Gen.set (Range.singleton numHeaders) genHeaderKey
|
|
|
|
genValues = S.toList <$> Gen.set (Range.singleton numHeaders) genHeaderValue
|
|
|
|
|
|
|
|
removeHeaders <- Gen.list (Range.constant 1 10) genHeaderKey
|
2022-03-23 23:23:46 +03:00
|
|
|
addOrReplaceHeaders <- liftA2 zip genKeys genValues
|
|
|
|
pure $ Headers.AddReplaceOrRemoveFields {addOrReplaceHeaders, removeHeaders}
|
2021-09-16 14:03:01 +03:00
|
|
|
|
2022-03-08 03:42:06 +03:00
|
|
|
genQueryParams :: Gen [(UnescapedTemplate, Maybe UnescapedTemplate)]
|
2021-09-16 14:03:01 +03:00
|
|
|
genQueryParams = do
|
|
|
|
numParams <- Gen.integral $ Range.constant 1 20
|
2022-03-08 03:42:06 +03:00
|
|
|
let keyGen = genUnescapedTemplate
|
|
|
|
valueGen = Gen.maybe $ genUnescapedTemplate
|
2021-09-16 14:03:01 +03:00
|
|
|
keys <- Gen.list (Range.singleton numParams) keyGen
|
|
|
|
values <- Gen.list (Range.singleton numParams) valueGen
|
2021-09-29 11:13:30 +03:00
|
|
|
pure $ nubBy (\a b -> fst a == fst b) $ zip keys values
|
|
|
|
|
2022-03-08 03:42:06 +03:00
|
|
|
genUrl :: Gen UnescapedTemplate
|
2021-09-29 11:13:30 +03:00
|
|
|
genUrl = do
|
|
|
|
host <- Gen.text (Range.constant 3 20) Gen.alphaNum
|
|
|
|
|
2022-03-08 03:42:06 +03:00
|
|
|
pure $ UnescapedTemplate $ "http://www." <> host <> ".com"
|
2021-09-16 14:03:01 +03:00
|
|
|
|
2022-03-23 23:23:46 +03:00
|
|
|
genRequestTransformDefunc :: Gen RequestTransformFns
|
2022-03-08 03:42:06 +03:00
|
|
|
genRequestTransformDefunc = do
|
|
|
|
method <- Gen.maybe genMethod
|
2021-09-16 14:03:01 +03:00
|
|
|
-- NOTE: At the moment no need to generate valid urls or templates
|
|
|
|
-- but such instances maybe useful in the future.
|
2022-03-23 23:23:46 +03:00
|
|
|
url <- Gen.maybe genUrl
|
|
|
|
body <- Gen.maybe genTemplate
|
|
|
|
queryParams <- Gen.maybe genQueryParams
|
|
|
|
headers <- Gen.maybe genTransformHeaders
|
2022-03-08 03:42:06 +03:00
|
|
|
pure
|
|
|
|
RequestFields
|
2022-03-23 23:23:46 +03:00
|
|
|
{ method = withOptional @MethodTransformFn (fmap Method.Replace method),
|
|
|
|
url = withOptional @UrlTransformFn (fmap Url.Modify url),
|
|
|
|
body = withOptional @BodyTransformFn (fmap Body.ModifyAsJSON body),
|
|
|
|
queryParams = withOptional @QueryParamsTransformFn (fmap QueryParams.AddOrReplace queryParams),
|
|
|
|
requestHeaders = withOptional @HeadersTransformFn (fmap Headers.AddReplaceOrRemove headers)
|
2022-03-08 03:42:06 +03:00
|
|
|
}
|
2022-03-23 23:23:46 +03:00
|
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- Helpers
|
|
|
|
|
|
|
|
-- | TODO: Move this out to a common module!
|
|
|
|
trippingJSON ::
|
|
|
|
forall a m.
|
|
|
|
(Show a, Eq a, ToJSON a, FromJSON a, MonadTest m) =>
|
|
|
|
a ->
|
|
|
|
m ()
|
|
|
|
trippingJSON val = tripping val toJSON fromJSON
|