Skip to main content

Directives

Directives let you transform and compose field values directly within your GraphQL query. They are applied to a special _fn field and can be chained left-to-right so that the output of one directive becomes the input of the next.

How Directives Work

Every directive is attached to a virtual _fn field inside a selection set. The first directive in the chain specifies where to pull input data using one of two arguments:

ArgumentTypeDescription
refStringA single dot-notation path to a field in the current object. Returns one value.
refs[String!]A list of dot-notation paths. Returns an array of values (one per path).

Subsequent directives in the chain ignore ref/refs and instead operate on the value returned by the previous directive.

tip

You can alias the _fn field (e.g. displayName: _fn @upper(ref: "names.edges.0.node.name")) to give the computed value a meaningful key in the response.


@coalesce

Returns the first non-null value from the referenced fields. Useful for falling back to alternative fields when the primary one is missing.

Arguments: ref | refs

Request
query {
search(
searchInput: {
name: "Enigma Technologies"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
primaryIdentifier: _fn @coalesce(refs: [
"websites.edges.0.node.website",
"names.edges.0.node.name"
])
websites {
edges {
node {
website
}
}
}
names {
edges {
node {
name
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"primaryIdentifier": "enigma.com",
"websites": {
"edges": [
{
"node": {
"website": "enigma.com"
}
}
]
},
"names": {
"edges": [
{
"node": {
"name": "ENIGMA TECHNOLOGIES"
}
}
]
}
}
]
}
}

@compact

Removes null values from an array. Non-array values pass through unchanged.

Arguments: ref | refs

Request
query {
search(
searchInput: {
name: "McDonald's"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
nonNullNames: _fn @compact(refs: [
"names.edges.0.node.name",
"names.edges.1.node.name",
"names.edges.2.node.name"
])
names(first: 3) {
edges {
node {
name
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"nonNullNames": [
"MCDONALD'S",
"MCDONALD'S RESTAURANT"
],
"names": {
"edges": [
{
"node": {
"name": "MCDONALD'S"
}
},
{
"node": {
"name": "MCDONALD'S RESTAURANT"
}
}
]
}
}
]
}
}

@slice

Returns a subset of an array or string by start and end index. Supports negative indices (e.g. end: -1 to exclude the last element).

Arguments:

ArgumentTypeDescription
startIntStart index (inclusive, defaults to 0).
endIntEnd index (exclusive, defaults to length). Negative values count from the end.
Request
query {
search(
searchInput: {
name: "McDonald's"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
abbreviated: _fn @slice(ref: "names.edges.0.node.name", end: 8)
names(first: 1) {
edges {
node {
name
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"abbreviated": "MCDONAL",
"names": {
"edges": [
{
"node": {
"name": "MCDONALD'S"
}
}
]
}
}
]
}
}

@trim

Strips leading and trailing whitespace from a string, or from each string in an array.

Arguments: ref | refs

Request
query {
search(
searchInput: {
name: "Enigma Technologies"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
cleanName: _fn @trim(ref: "names.edges.0.node.name")
names(first: 1) {
edges {
node {
name
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"cleanName": "ENIGMA TECHNOLOGIES",
"names": {
"edges": [
{
"node": {
"name": "ENIGMA TECHNOLOGIES"
}
}
]
}
}
]
}
}

@upper

Converts a string to UPPERCASE, or each string in an array to uppercase.

Arguments: ref | refs

Request
query {
search(
searchInput: {
name: "Enigma Technologies"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
shout: _fn @upper(ref: "websites.edges.0.node.website")
websites(first: 1) {
edges {
node {
website
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"shout": "ENIGMA.COM",
"websites": {
"edges": [
{
"node": {
"website": "enigma.com"
}
}
]
}
}
]
}
}

@lower

Converts a string to lowercase, or each string in an array to lowercase.

Arguments: ref | refs

Request
query {
search(
searchInput: {
name: "McDonald's"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
loweredName: _fn @lower(ref: "names.edges.0.node.name")
names(first: 1) {
edges {
node {
name
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"loweredName": "mcdonald's",
"names": {
"edges": [
{
"node": {
"name": "MCDONALD'S"
}
}
]
}
}
]
}
}

@map

Extracts a nested field from each element in an array. The field argument is a dot-separated path. Returns null for elements where the path does not exist.

Arguments:

ArgumentTypeDescription
ref | refsString | [String!]The source array to iterate over.
fieldStringDot-notation path to extract from each element (e.g. "node.name").

This example pulls from two sources (websites and operatingLocations), extracts the first technology from each, removes nulls with @compact, and joins them into a comma-separated string. The raw source fields are hidden from the response using @skip(if: true).

Request
query Search {
search(
searchInput: {
name: "TATSU SUSHI"
entityType: BRAND
address: {
street1: ""
street2: null
city: "WALNUT CREEK"
state: "CA"
postalCode: "94598"
}
}
) {
... on Brand {
id
technologies: _fn
@map(refs: ["websites", "operatingLocations"], field: "edges.0.node.technologiesUseds.edges.0.node.technology")
@compact
@join(sep: ",")
websites(conditions: {filter: {HAS: ["technologiesUseds"]}}) @skip(if: true) {
edges {
node {
technologiesUseds {
edges {
node {
technology
}
}
}
}
}
}
operatingLocations(conditions: {filter: {HAS: ["technologiesUseds"]}}) @skip(if: true) {
edges {
node {
technologiesUseds {
edges {
node {
technology
}
}
}
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"id": "some-brand-id",
"technologies": "SQUARE,DOORDASH"
}
]
}
}
tip

Use @skip(if: true) on the source fields to keep your response clean — the directives still read from those fields before they are stripped from the output.


@join

Joins array elements into a single string using the specified separator. Null values become empty strings; non-string values are stringified.

Arguments:

ArgumentTypeDescription
ref | refsString | [String!]The source values to join.
sepStringSeparator inserted between elements (defaults to "").
Request
query {
search(
searchInput: {
name: "McDonald's"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
nameList: _fn @join(refs: [
"names.edges.0.node.name",
"names.edges.1.node.name",
"names.edges.2.node.name"
], sep: " | ")
names(first: 3) {
edges {
node {
name
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"nameList": "MCDONALD'S | MCDONALD'S RESTAURANT | MCDONALDS",
"names": {
"edges": [
{
"node": {
"name": "MCDONALD'S"
}
},
{
"node": {
"name": "MCDONALD'S RESTAURANT"
}
},
{
"node": {
"name": "MCDONALDS"
}
}
]
}
}
]
}
}

@include

Includes a field or fragment only when the if argument is true. This is a standard GraphQL directive that works on fields and fragments directly (not via _fn).

Arguments:

ArgumentTypeDescription
ifBoolean!When true, the annotated field is included in the response.
Request
query {
search(
searchInput: {
name: "McDonald's"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
names(first: 1) {
edges {
node {
name
}
}
}
websites(first: 1) @include(if: true) {
edges {
node {
website
}
}
}
operatingLocations(first: 1) @include(if: false) {
edges {
node {
addresses(first: 1) {
edges {
node {
fullAddress
}
}
}
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"names": {
"edges": [
{
"node": {
"name": "MCDONALD'S"
}
}
]
},
"websites": {
"edges": [
{
"node": {
"website": "mcdonalds.com"
}
}
]
}
}
]
}
}
note

operatingLocations is completely absent from the response because @include(if: false) excluded it. In practice, @include is most useful when the if value is driven by a query variable (e.g. @include(if: $withLocations)).


@skip

Excludes a field or fragment when the if argument is true. This is the inverse of @include and is a standard GraphQL directive that works on fields and fragments directly (not via _fn).

Arguments:

ArgumentTypeDescription
ifBoolean!When true, the annotated field is omitted from the response.
Request
query {
search(
searchInput: {
name: "McDonald's"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
names(first: 1) {
edges {
node {
name
}
}
}
websites(first: 1) @skip(if: true) {
edges {
node {
website
}
}
}
operatingLocations(first: 1) @skip(if: false) {
edges {
node {
addresses(first: 1) {
edges {
node {
fullAddress
}
}
}
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"names": {
"edges": [
{
"node": {
"name": "MCDONALD'S"
}
}
]
},
"operatingLocations": {
"edges": [
{
"node": {
"addresses": {
"edges": [
{
"node": {
"fullAddress": "106 WOLF RD ALBANY NY 12205"
}
}
]
}
}
}
]
}
}
]
}
}
note

websites is absent from the response because @skip(if: true) excluded it, while operatingLocations is present because @skip(if: false) kept it. In practice, @skip is most useful when the if value is driven by a query variable (e.g. @skip(if: $hideWebsites)).


Chain Directives Together

Directives can be chained on a single _fn field. When chained, the output of each directive is passed as input to the next one, left-to-right. Only the first directive in the chain uses ref/refs to read from the response data — the rest operate on the previous directive's output.

Extract, lowercase, trim, and join brand names

This example uses @map to extract each name from the edges array, then @lower to lowercase them, @trim to strip whitespace, and finally @join to combine them into a single comma-separated string.

Request
query {
search(
searchInput: {
name: "McDonald's"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
combinedNames: _fn
@map(ref: "names.edges", field: "node.name")
@lower
@trim
@join(sep: ", ")
names(first: 3) {
edges {
node {
name
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"combinedNames": "mcdonald's, mcdonald's restaurant, mcdonalds",
"names": {
"edges": [
{
"node": {
"name": "MCDONALD'S"
}
},
{
"node": {
"name": "MCDONALD'S RESTAURANT"
}
},
{
"node": {
"name": "MCDONALDS"
}
}
]
}
}
]
}
}

Extract addresses, uppercase, and take the first two

This example extracts the fullAddress from each operating location's address edges, uppercases them, and slices to keep only the first two results.

Request
query {
search(
searchInput: {
name: "McDonald's"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
topTwoAddresses: _fn
@map(ref: "operatingLocations.edges", field: "node.addresses.edges.0.node.fullAddress")
@compact
@upper
@slice(start: 0, end: 2)
operatingLocations(
conditions: {
filter: {
AND: [
{ EQ: ["addresses.city", "ALBANY"] }
{ EQ: ["addresses.state", "NY"] }
]
}
}
) {
edges {
node {
addresses(first: 1) {
edges {
node {
fullAddress
}
}
}
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"topTwoAddresses": [
"106 WOLF RD ALBANY NY 12205",
"161 WASHINGTON EXT AVE ALBANY NY 12205"
],
"operatingLocations": {
"edges": [
{
"node": {
"addresses": {
"edges": [
{
"node": {
"fullAddress": "106 WOLF RD ALBANY NY 12205"
}
}
]
}
}
},
{
"node": {
"addresses": {
"edges": [
{
"node": {
"fullAddress": "161 WASHINGTON EXT AVE ALBANY NY 12205"
}
}
]
}
}
},
{
"node": {
"addresses": {
"edges": [
{
"node": {
"fullAddress": "256 OSBORNE RD ALBANY NY 12211"
}
}
]
}
}
}
]
}
}
]
}
}

Coalesce with a fallback, then uppercase

Pick the website if available, otherwise fall back to the brand name, then uppercase the result.

Request
query {
search(
searchInput: {
name: "Enigma Technologies"
entityType: BRAND
conditions: { limit: 1 }
}
) {
... on Brand {
displayLabel: _fn
@coalesce(refs: [
"websites.edges.0.node.website",
"names.edges.0.node.name"
])
@upper
websites(first: 1) {
edges {
node {
website
}
}
}
names(first: 1) {
edges {
node {
name
}
}
}
}
}
}
Response
{
"data": {
"search": [
{
"displayLabel": "ENIGMA.COM",
"websites": {
"edges": [
{
"node": {
"website": "enigma.com"
}
}
]
},
"names": {
"edges": [
{
"node": {
"name": "ENIGMA TECHNOLOGIES"
}
}
]
}
}
]
}
}