Skip to main content

intro

Directives

Directives are small functions for accessing and manipulating data, composable in pipelines to achieve more complex transformations. Their primary use case is for mapping arguments and results in resolver configurations.

They have a minimal set of options and can access the values in the currentQuery context.

type Directive = [
function: string,
{
[key: string]: string;
}
];

Find all the directives in [api/src/lib/graphql-v3/directives.ts](https://github.com/takeshape/takeshape/blob/71cb27d61fc1f3f19fc15eced195da40a0c17937/packages/api/src/lib/graphql-v3/directives.ts)

set

This simple directive returns the provided value as a string. It's great for directly setting a literal value, or for starting off a directive pipeline with a value available in the currentQuery syntax.

Options

  • value required

    The string that should be set.

get

In its simplest form, get will get the value at path and pass it into the directive pipeline. Most directives pipelines start with get and the mapping shorthand is itself a get operation. If the value at path evaluates to undefined the value of $previousDirective, if any, will be sent on. If a defaultValue is set, this will be passed on instead.

get can also take an array of string paths. In this case it will return multiple values. This can be useful for further directives, like format or zipAndMerge.

Finally, get supports tokens, which are evaluated against the context, in the path. This allows for extended logic, like using a $loop.key to maintain a reference to the same array item in a loop. A path with a token looks like this: $finalResolver[{$loop.key}].params[{$args.someParamName}]. See the examples below for more.

Under the hood, get uses jsonpath-plus so you have a fair amount of power getting values into your directive.

Options

  • path (string | string[], required) This is property path to get from the context.

  • defaultValue (any, optional) A value to use if the path returns undefined

  • passThroughOnUndefined (boolean, optional) If path returns undefined, and no defaultValue is set, return the previous value. Defaults to true.

  • flatten (boolean, optional) When your path returns a multidimensional array, flatten it to a single dimension. For example, if the path $args.colors[*] returned [['Red'], ['Blue']] setting flatten would instead return ['Red', 'Blue'] to the directive pipeline.

  • wrap (boolean, optional) Whether to wrap your results in an array. Default is false, so only actual array results will return an array, otherwise you'll get the primitive value as-is. For example, if the path $args.page contained the number 5, setting wrap would instead return [5] to the directive pipeline.

Example

In the example below, input.title would be set to the value of either the takeshapeUpdate or takeshapeCreate step, if one is undefined and the other has a value. If both have a value, input.title will be the value of takeshapeCreate since that step is run later in the pipeline.

If we disabled passThroughOnUndefined and the takeshapeCreate step returned undefined our result would be undefined, not the value of takeshapeUpdate.

{
"args": {
"ops": [
{
"path": "input.title",
"mapping": [
["get", {"path": "$resolvers.takeshapeUpdate.result.name"}],
["get", {"path": "$resolvers.takeshapeCreate.result.name"}]
]
},
{
"path": "input.vendor",
"mapping": [["get", {"path": "$resolvers.takeshapeCreate.result.vendor", "defaultValue": "Kirkland"}]]
}
]
}
}

And in this example, we're getting multiple values and passing them to the format directive. Each of the values returns a string.

{
"results": {
"ops": [
{
"path": "name",
"mapping": [
["get", {"path": ["$resolvers.takeshapeUpdate.result.name", "$args.nameSuffix"]}],
["format", {"template": "%s, %s"}]
]
}
]
}
}

In the following example, we'll use path tokens to maintain the same index in a source array while populating a results array.

{
"results": {
"ops": [
{
"path": "items",
"mapping": [
["get", {"path": "$finalResolver.length"}],
["array", {}]
]
},
{
"path": "items[*].newParams",
"mapping": [["get", {"path": "$finalResolver[{$loop.key}].params"}]]
}
]
}
}

trim

Removes matching leading and trailing characters from a string.

Options

  • **chars** Defines the leading and trailing characters to remove from a string. For example, if you want to remove quotes from a string. Defaults to remove whitespace characters.

toUpper

Converts the string, as a whole, to upper case.

prepend

Prepends the text provided in options to the string.

Options

  • **text** required The text you'd like to prepend to the string

expressionEval

Use the expression-eval module and our own custom context.

Options

  • expression ****required

Context

  • The same currentQuery context from above, plus
  • A number of callable functions
    • ~180 functions exported from lodash/fp, for the full list view api/src/lib/graphqlv3/expressions-functions
    • format exported from util
    • mapDeep a custom function for deep mappings, for example, all [foo.name](http://foo.name) object paths at any depth in an array of objects
    • newObject provides a new object, given the limitations of the expression evaluation approach
    • getImageUrl from @takeshape/routing

zipAndMerge

zipWith from lodash, using merge also from lodash to deeply merge objects at the same indexes in multiple arrays.

This will operate on whatever was output from the directive at the previous step, but is a noop if that value is not an array.

replace

Replaces patterns or a regexp in a string provided by the $previousDirective.

replace from lodash.

Options

  • replacement (string, required)
  • pattern (string, required if no regexp)
  • regexp (string, required if no pattern)
  • regexpFlag (string, optional)

filter

Filters any string, array or object passed in from the $previousDirective.

filter from lodash.

Options

  • predicate (string | Object | Array, required if no expression)

    • A lodash.filter iteratee predicates.
  • expression (string, required if no predicate)

    • An expressionEval expression as described above. You have access to the full query context, and get the additional context variables $value, $index and $collection for comparison. For example, $value.species !== 'Human' would compare the species property in an object to the literal string Human.

    • If you happen to be using a string as your input, the iteratee context variables will be $char, $index and $string.

format

A printf-like format utility, using util.formatWithOptions from the Node.js standard library.

If the $previousDirective provides an array, that array will be spread onto the params of util.formatWithOptions. If a non-array value is found it will be supplied as the single param for formatting.

Options

  • template (string, required)

    • A string with replacement specifiers. Common specifiers are %s for a string, and %d for a number. A full list can be found here.
  • options (Object, optional)

    • Options for util.inspect. Full list here.

array

A utility for initializing an array. The array directive takes a single option, initial which will be the value passed to the Array constructor. If no initial option is set, the results of the $previousDirective are used instead.

If the number passed is a number, then an array of that length will be initialized. Any other value will be set as the sole element of the new array.

If both initial and $previousDirective are undefined, an empty array will be returned.

Options

  • initial (any, optional)

    • An optional value to set as the initial value in the Array constructor.

Examples

One of the most useful applications of this directive is to initialize ops values of a length equivalent to some other iterable value in your context. In this example, if your $finalResolver was an array of 10 items, your results item path will be initialized with an empty array of length 10.

{
"results": {
"ops": [
{
"path": "items",
"mapping": [
["get", {"path": "$finalResolver.length"}],
["array", {}]
]
},
{
"path": "items[*].newParams",
"mapping": [["get", {"path": "$finalResolver[{$loop.key}].params"}]]
}
]
}
}

md5

Compute the md5 hash of $previousDirective or value.

Options

  • value (string, optional)

Examples

In this example we create an composite id. First we get several properties of the source object, we then concatenate them and finally we hash the result to create a shorter id.

{
"id": {
"@tag": "id",
"@resolver": {
"name": "debug:noop",
"service": "takeshape:local",
"results": {
"ops": [
{
"path": "$",
"mapping": [
["get", {"path": ["$source.company", "$source.jobtitle", "$source:city"]}],
["format", {"template": "%s:%s:%s"}],
["md5", {}]
]
}
]
}
}
}
}

sha1

Compute the sha1 hash of $previousDirective or value.

Options

  • value (string, optional)

sha256

Compute the sha256 hash of $previousDirective or value.

Options

  • value (string, optional)

encodeBase64

Encode $previousDirective or value from utf8 into base64

Options

  • value (string, optional)

decodeBase64

Decode $previousDirective or value from base64 into utf8

Options

  • value (string, optional)