diff --git a/CHANGELOG.md b/CHANGELOG.md index f262438a6b376..0b114efe61c49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -292,7 +292,6 @@ Further changes are forthcoming along similar lines. - build: Changes to the `hasura/graphql-engine` Docker image: - Default graphql-engine docker images (`hasura/graphql-engine:`) now use an Ubuntu base instead of Debian. - Debian flavour of images (`hasura/graphql-engine:.debian`) are still published to Docker Hub. - - CentOS flavour of images (`hasura/graphql-engine:.centos`) are no longer supported. ## v2.10.0-beta.1 @@ -560,7 +559,8 @@ Please submit any feedback you may have for this feature at https://github.com/h - Default graphql-engine docker images (`hasura/graphql-engine:`) now use an Ubuntu base instead of Debian. - Debian flavour of images (`hasura/graphql-engine:.debian`) are still published to Docker Hub. - CentOS flavour of images (`hasura/graphql-engine:.centos`) are no longer supported. - +- docs: Kriti templating documentation sections added + ## v2.9.0 ### Event Triggers for MS SQL Server diff --git a/docs/docs/actions/rest-connectors.mdx b/docs/docs/actions/rest-connectors.mdx index aada92c017fc6..4888de45c9725 100644 --- a/docs/docs/actions/rest-connectors.mdx +++ b/docs/docs/actions/rest-connectors.mdx @@ -23,7 +23,14 @@ REST Connectors for actions are used to integrate existing REST APIs to the Grap or modifications to the upstream code. REST Connectors modify the default HTTP request made by an action to adapt to your webhook's expected format by adding -suitable transforms. +suitable transforms. + +:::info Note + +General information about the templating used in REST Connectors can be found in the +[Kriti templating](/api-reference/kriti-templating.mdx) section of the documentation. + +::: :::tip Supported from @@ -135,6 +142,13 @@ The context variables available in transforms are: | $base_url | Original configured webhook handler URL | | $session_variables | Session variables | +In addition to these variables, the following functions are available in addition to the +standard [Basic Functions](/api-reference/kriti-templating.mdx#kriti-function-reference): + +| Context variable | Value | +|----------------------------|-------------------------------------------------------| +| `getSessionVariable(NAME)` | Look up a session variable by name (case-insensitive) | + #### Console sample context {#action-transforms-sample-context} The console allows you to preview your transforms while configuring them. To avoid exposing sensitive information on the diff --git a/docs/docs/api-reference/cloud-api-reference.mdx b/docs/docs/api-reference/cloud-api-reference.mdx index 1ebcf26b2238e..1d45d5f4515f9 100644 --- a/docs/docs/api-reference/cloud-api-reference.mdx +++ b/docs/docs/api-reference/cloud-api-reference.mdx @@ -6,7 +6,7 @@ keywords: - docs - API - API reference -sidebar_position: 13 +sidebar_position: 14 sidebar_label: Hasura Cloud API Reference sidebar_class_name: cloud-icon --- diff --git a/docs/docs/api-reference/kriti-templating.mdx b/docs/docs/api-reference/kriti-templating.mdx new file mode 100644 index 0000000000000..a2e73fce285b2 --- /dev/null +++ b/docs/docs/api-reference/kriti-templating.mdx @@ -0,0 +1,578 @@ +--- +description: Templating with Kriti +keywords: + - hasura + - docs + - postgres + - mutation +sidebar_label: Kriti Templating +sidebar_position: 13 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import Thumbnail from "@site/src/components/Thumbnail"; +import TOCInline from '@theme/TOCInline'; + +# Kriti Templating in Hasura + +## Introduction + +Kriti allows transoformation of JSON via templating during the Hasura GraphQL Engine lifecycle. + +:::info Note + +See [Kriti's README.md on Github](https://github.com/hasura/kriti-lang#kriti-lang) for additional details. + +::: + +Kriti has a JSON-like syntax that allows for the creation of JSON values via direct-construction, reference and branching structures. + +There are two main ways that Kriti templates are used: + +* String interpolation for fields +* Payload transformation + +String interpolation can also be used inside Kriti payload transformations, so only payload examples will be used here. But note that when a field provides Kriti interpolation capabilities you can't use the full capabilities of Kriti templates, just the interpolation capabilities. + +At present, Kriti templating is available for: + +* [Action REST Connectors](/actions/rest-connectors.mdx) +* [Scheduled Triggers](/scheduled-triggers/index.mdx) +* [Event Triggers](/event-triggers/index.mdx) + +## Capabilities and behavior + +The functionality of Kriti templates can be broken down into the following categories: + +* JSON Value Construction +* Control Flow +* Value Interpolation +* String Interpolation +* Path Accessors +* Optional Chaining +* Functions + +Most Kriti-specific functionality is introduced through the use of a `{{ ... }}` syntax. + +### JSON value construction + +To construct JSON values in a Kriti template, you write JSON as usual. + +For exampe, the following is a valid Kriti template and JSON document: + +```json +{ + "a": [1,2,3], + "b": "hello world" +} +``` +### Value interpolation + +Values can be interpolated in place of a normal JSON value. For example, the "b" field uses interpolation rather than a literal value here: + +```json +{ + "a": 1, + "b": {{ 2 }} +} +``` + +### String interpolation + +Values can also be interpolated inside strings: + +```json +"Hello world {{ 1 }}" +``` + +### Control flow + +Conditional logic and loops are supported: + +```json +{ + "if" : {{ if something }} 1 {{ else }} 2 {{ end }}, + "loop": {{ range i, x := [1,2,3] }} ["item", {{ i }}, {{ x }}] {{ end }} +} +``` + +### Path references + +As part of interpolation and control-flow you may reference data via paths, of which a variable is a special case. The scope from which a path is looked up is either top-level, or expanded via control flow. + +For example, if the variable `foo` contained the value `1`, you could reference it like so: + +```json +{ "a": {{ foo }} } +``` + +If the variable `bar` contained the value `{"x": 2}`, you could reference it like so: + +```json +{ "a": {{ bar.x }} } +``` + +or: + +```json +{ "a": {{ bar['x'] }} } +``` + +### Optional chaining + +You may also use optional chaining to traverse into fields that may not be present. The value is `Null` if the field is not present: + +```json +{ "a": {{ bar?.x }} } +``` + +or: + +```json +{ "a": {{ bar?['x'] }} } +``` + +`Null` values can be defaulted via the `??` operator: + +```json +{ "a": {{ bar?.y ?? 3 }} } +``` + +### Functions + +Functions can be invoked from Kriti templates to interact with values. + +These use the `foo(...)` syntax: + +```json +{ + "a": {{ concat([[1,2],[3,4]]) }} +} +``` + +The [Function Reference](#kriti-function-reference) section details the functions available by default. Note that there can be additional functions and values in the scope depending on the template context. These will be documented in the relevant documentation section. + +## Example + +One Hasura feature that utilizes Kriti templates is REST Connectors. + + + + +Open the Hasura Console, head to the `Actions` tab, and click the `Create` button to open the page. + +Add a REST connector payload and configure and test the associated template. + + + + + + + +An API call to create an action can include an associated template to process the action handler's response: + +```http +POST /v1/metadata HTTP/1.1 +Content-Type: application/json +X-Hasura-Role: admin + +{ + "type": "create_action", + "args": { + "name": "actionName", + "definition": { + "arguments": [ + { + "name": "arg1", + "type": "SampleInput!" + } + ], + "kind": "synchronous", + "output_type": "SampleOutput", + "handler": "http://httpbin.org", + "type": "mutation", + "headers": [], + "timeout": null, + "request_transform": { + "version": 2, + "template_engine": "Kriti", + "method": null, + "query_params": {}, + "body": { + "action": "transform", + "template": "{\n \"users\": {\n \"name\": {{$body.input.arg1.username}},\n \"password\": {{$body.input.arg1.password}}\n }\n}" + }, + "content_type": "application/json" + } + } + } +} +``` + +The template field is a string that represents a template in the language reflected in the template_engine field. +In this case: + +```json +{ + "users": { + "name": {{.input.arg1.username}}, + "password": {{.input.arg1.password}} + } +} +``` + + + +## Function reference {#kriti-function-reference} + +The following functions are available for use in all Kriti templates: + +### empty + +Returns `true` if an object, array, or string is empty, if a number is 0, or if the object is `null`. + +Raises an error for booleans. + +Input: + +```json +{ + "object": {{ empty({"a": 1}) }}, + "string": {{ empty("") }}, + "array": {{ empty([1]) }} +} +``` + +Output: + +```json +{ + "array": false, + "object": false, + "string": true +} +``` + +### size + +Returns: +- the length of an array or string +- the number of keys of an object +- the value of a number +- `1` for `true` and `0` for `false` +- `0` for `null` + +Input: + +```json +{ + "object": {{ size({"a": 1}) }}, + "string": {{ size("asdf") }}, + "array": {{ size([1]) }} +} +``` + + Output: + +```json +{ + "array": 1, + "object": 1, + "string": 4 +} +``` + +### inverse + +- Reverses an array or string +- Leaves an object or `null` as-is +- Takes the reciprical of a number +- Negates a boolean + +Input: + +```json +{ + "string": {{ inverse("asdf") }}, + "array": {{ inverse([1,2,3]) }}, + "number": {{ inverse(4) }} +} +``` + +Output: + +```json +{ + "array": [ + 3, + 2, + 1 + ], + "number": 0.25, + "string": "fdsa" +} +``` + +### head + +Takes the first element or character of an array or string. + +Throws an error if they are empty, and throws an error for all other types. + +Input: + +```json +{ + "string": {{ head("asdf") }}, + "array": {{ head([1,2,3]) }} +} +``` + +Output: + +```json +{ + "array": 1, + "string": "a" +} +``` + +### tail + +Drops the first element of an array or string. + +Throws an error for all other types. + +Input: + +```json +{ + "string": {{ tail("asdf") }}, + "array": {{ tail([1,2,3]) }} +} +``` + +Output: + +```json +{ + "array": [ + 2, + 3 + ], + "string": "sdf" +} + +``` + +### toCaseFold + +Converts a string to a normalized casing (useful for case-insensitive string comparison). + +Throws an error for non-strings. + +Input: + +```json +{ + "string": {{toCaseFold("AbCd")}} +} +``` + +Output: + +```json +{ + "string": "abcd" +} +``` + +### toLower + +Converts a string to lower-case. + +Throws an error for non-strings. + +Input: + +```json +{ + "string": {{toLower("AbCd")}} +} +``` + +Output: + +```json +{ + "string": "abcd" +} + +``` + +### toUpper + +Converts a string to upper-case. + +Throws an error for non-strings. + +Input: + +```json +{ + "string": {{toUpper("AbCd")}} +} +``` + +Output: + +```json +{ + "string": "ABCD" +} + +``` + +### toTitle + +Converts a string to title-case. + +Throws an error for non-strings. + +Input: + +```json +{ + "string": {{toTitle("AbCd")}} +} +``` + +Output: + +```json +{ + "string": "Abcd" +} +``` + +### fromPairs + +Convert an array like `[ [a,b], [c,d] ... ]` to an object like `{ a:b, c:d ... }`. + +Input: + +```json +{ + "array": {{ fromPairs([["a",1],["b",2]]) }} +} +``` + +Output: + +```json +{ + "array": { + "a": 1, + "b": 2 + } +} +``` + +### toPairs + +Converts an object like `{ a:b, c:d ... }` to an array like `[ [a,b], [c,d] ... ]`. + +Input: + +```json +{ + "object": {{ toPairs({"a": 1, "b": 2}) }} +} +``` + +Output: + +```json +{ + "object": [ + [ + "a", + 1 + ], + [ + "b", + 2 + ] + ] +} +``` + +### removeNulls + +Removes `null` items from an array. + +Input: + +```json +{ + "array": {{ removeNulls([1,null,3,null,5]) }} +} +``` + +Output: + +```json +{ + "array": [ + 1, + 3, + 5 + ] +} +``` + +### concat + +Concatenates a string, array, or object. + +For object key collisions, values from right-most objects are used. + +Input: + +```json +{ + "arrays": {{ concat([[1,2],[3,4]]) }}, + "strings": {{ concat(["abc", "def", "g"]) }}, + "objects": {{ concat([{"a":1, "b":2},{"b":3, "c":4} ] ) }} +} +``` + +Output: + +```json +{ + "arrays": [ + 1, + 2, + 3, + 4 + ], + "objects": { + "a": 1, + "b": 3, + "c": 4 + }, + "strings": "abcdefg" +} +``` + +:::info Note + +All of the above functions are also listed on the [Kriti Github README.md](https://github.com/hasura/kriti-lang/blob/main/README.md#basic-functions-collection). + +::: + diff --git a/docs/docs/event-triggers/rest-connectors.mdx b/docs/docs/event-triggers/rest-connectors.mdx index 3c80a9d3b0a87..b1f96edce72cd 100644 --- a/docs/docs/event-triggers/rest-connectors.mdx +++ b/docs/docs/event-triggers/rest-connectors.mdx @@ -19,11 +19,18 @@ import Thumbnail from '@site/src/components/Thumbnail'; ## Introduction REST Connectors for event triggers are used to invoke existing or third-party webhooks without needing any middleware or -modifications to the upstream code. +modifications to the upstream code. REST Connectors modify the event trigger's HTTP request to adapt to your webhook's expected format by adding suitable transforms. +:::info Note + +General information about the templating used in REST Connectors can be found in the +[Kriti templating](/api-reference/kriti-templating.mdx) section of the documentation. + +::: + :::tip Supported from REST Connectors are supported in Hasura GraphQL Engine versions `v2.1.0` and above. diff --git a/docs/docs/scheduled-triggers/index.mdx b/docs/docs/scheduled-triggers/index.mdx index c8c9aa5a0d1b9..cfcc85428723a 100644 --- a/docs/docs/scheduled-triggers/index.mdx +++ b/docs/docs/scheduled-triggers/index.mdx @@ -28,6 +28,11 @@ Scheduled triggers are supported from versions `v1.3.0` and above. ::: +## Request and response transformations + +Scheduled triggers support transformations as per REST Connectors. Currently this functionality +is only available through [Metadata APIs](/api-reference/metadata-api/scheduled-triggers.mdx). + ## Types There are two types of timed events: diff --git a/docs/static/img/graphql/core/templates/create-action-configure-rest-connectors.png b/docs/static/img/graphql/core/templates/create-action-configure-rest-connectors.png new file mode 100644 index 0000000000000..3e046e1f24656 Binary files /dev/null and b/docs/static/img/graphql/core/templates/create-action-configure-rest-connectors.png differ