Directives
Directives are a GraphQL feature that affect the execution of a query in any way the server desires. Directives can be attached to different parts of the schema (field, fragment inclusion, etc.). There are several core GraphQL directives:
| Directive | Attached to | Description |
|---|---|---|
@include | field, fragment inclusion | Only include this field in the result if the argument is true. |
@skip | field, fragment inclusion | Skip this field if the argument is true. |
In addition, we provide custom directives:
| Directive | Attached to | Description |
|---|---|---|
@export | field, fragment inclusion | Export the value of a field into a variable that can be used somewhere else in the query. |
@dependsOn | field, fragment inclusion | Specify that a field depends on another field. |
The @include directive
Includes a field or fragment in the result only if the Boolean argument is true.
Syntax:
@include(if: Boolean!)Example:
query($cid : Int!, $pagesize : Int, $withdetails : Boolean!)
{
useCompany(no : $cid)
{
order(first : $pagesize)
{
totalCount
items
{
orderNo
orderDate
lines : joindown_OrderLine_via_Order(first: 2) @include(if: $withdetails)
{
totalCount
items
{
lineNo
transactionDate
}
}
}
}
}
}Result:
{
"data": {
"useCompany": {
"order": {
"totalCount": 451,
"items": [
{
"orderNo": 1,
"orderDate": 20210212
},
{
"orderNo": 2,
"orderDate": 20130203
}
]
}
}
}
}{
"data": {
"useCompany": {
"order": {
"totalCount": 451,
"items": [
{
"orderNo": 1,
"orderDate": 20210212,
"lines": {
"totalCount": 6,
"items": [
{
"lineNo": 1,
"transactionDate": 0
},
{
"lineNo": 2,
"transactionDate": 0
}
]
}
},
{
"orderNo": 2,
"orderDate": 20130203,
"lines": {
"totalCount": 5,
"items": [
{
"lineNo": 1,
"transactionDate": 20140904
},
{
"lineNo": 2,
"transactionDate": 20140904
}
]
}
}
]
}
}
}
}The @skip directive
Skips a field if the Boolean argument is true.
Syntax:
@skip(if: Boolean!)Example:
query($cid : Int!, $pagesize : Int, $nodetails : Boolean!)
{
useCompany(no : $cid)
{
order(first : $pagesize)
{
totalCount
items
{
orderNo
orderDate
lines : joindown_OrderLine_via_Order(first: 2) @skip(if: $nodetails)
{
totalCount
items
{
lineNo
transactionDate
}
}
}
}
}
}Result:
{
"data": {
"useCompany": {
"order": {
"totalCount": 451,
"items": [
{
"orderNo": 1,
"orderDate": 20210212
},
{
"orderNo": 2,
"orderDate": 20130203
}
]
}
}
}
}{
"data": {
"useCompany": {
"order": {
"totalCount": 451,
"items": [
{
"orderNo": 1,
"orderDate": 20210212,
"lines": {
"totalCount": 6,
"items": [
{
"lineNo": 1,
"transactionDate": 0
},
{
"lineNo": 2,
"transactionDate": 0
}
]
}
},
{
"orderNo": 2,
"orderDate": 20130203,
"lines": {
"totalCount": 5,
"items": [
{
"lineNo": 1,
"transactionDate": 20140904
},
{
"lineNo": 2,
"transactionDate": 20140904
}
]
}
}
]
}
}
}
}The @export directive
The @export directive in GraphQL exports the value of a field into a variable that is used somewhere else in the query. This can be either a single value or an array.
Syntax:
@export(as: "variablename", distinct : true)Example: Fetch the cutomer number of the associate whose indentifier is specified and then use the customer number to fetch orders.
query($cid : Int!,
$ano : Int!,
$pagesize: Int,
$customerId : Int = 0)
{
useCompany(no: $cid)
{
associate(filter : {associateNo : {_eq: $ano}})
{
items
{
customerNo @export(as: "customerId")
}
}
order(first : $pagesize,
filter : {customerNo : {_eq : $customerId}})
{
totalCount
items
{
orderNo
orderDate
customerNo
}
}
}
}{
"data": {
"useCompany": {
"associate": {
"items": [
{
"customerNo": 10000
}
]
},
"order": {
"totalCount": 14,
"items": [
{
"orderNo": 81,
"orderDate": 20150115,
"customerNo": 10000
}
]
}
}
}
}Example: Add one order and two order lines for the order with a single request.
mutation ($cid: Int,
$cno : Int,
$pid1 : String,
$pid2 : String,
$orderId: Int = 0)
{
useCompany(no: $cid)
{
order_create(
values: [
{
orderDate: 20221104,
customerNo: $cno,
orderType: 1,
transactionType: 1
}
]
)
{
affectedRows
items
{
orderNo @export(as: "orderId")
}
}
orderLine_create(
values: [
{
orderNo: $orderId,
productNo: $pid1,
quantity: 1
},
{
orderNo: $orderId,
productNo: $pid2,
quantity: 2
}
]
)
{
affectedRows
items
{
lineNo
orderNo
productNo
}
}
}
}{
"data": {
"useCompany": {
"order_create": {
"affectedRows": 1,
"items": [
{
"orderNo": 632
}
]
},
"orderLine_create": {
"affectedRows": 2,
"items": [
{
"lineNo": 1,
"orderNo": 632,
"productNo": "1001"
},
{
"lineNo": 2,
"orderNo": 632,
"productNo": "1002"
}
]
}
}
}
}There are several things to keep in mind when using this directive:
- The variable into which the field value is exported must be defined in the query parameter list. Otherwise, when you use the variable later on in another part of the query, the server will complain that it is not defined.
- You can only export the value of one field into one variable. If you attempt to write values from multiple fields into the same variable they will be overwritten based of the order of evaluation.
- If you export multiple values into the same variable, the last field that is evaluated will define the value of the variable.
- If the variable is defined as an array, you can store multiple values.
In the previous examples, we have used a variable that could store a single value. Therefore, if a query returned multiple elements, a field would get evaluated multiple times and each time the variable would be overritten. The value from the last evaluation is the one that is finally stored in the variable.
However, all the values can be preserved in an array. The only change is that you need to define the variable of an array type. Moreover, you can use the Boolean optional argument distinct to retain only the distict values and discard duplicates. An array variable can be used for instance with the _in and _not_in filters.
The following example shows a query that fetches information about all the orders that have lines that were updated after a given moment in time:
query read_modified_orders($cid : Int!, $dt : DateTime,
$ono : [Int] = [])
{
useCompany(no : $cid)
{
orderLine(filter : {changedDateTime : {_gt : $dt}})
{
items
{
orderNo @export(as : "ono", distict : true)
}
}
order(filter : {orderNo : {_in : $ono})
{
items
{
orderNo
orderDate
customerNo
}
}
}
}Ordering and @export
In most cases the consuming field references the exported variable in its arguments, either directly or nested inside an input object or list. When that happens, the server picks up the reference and evaluates the consuming field after the exporting one. The examples above work this way: the order(filter: {customerNo: {_eq: $customerId}}) argument references the customerId exported just above it, and orderLine_create does the same with orderId.
For ordering requirements that are not visible from the arguments, use @dependsOn, described next.
The @dependsOn directive
The @dependsOn directive specifies that a field depends on another field and must be executed after it. To optimize execution the server packs independent fields together before sending them to the back-end, which can shuffle the visible order of fields in the query. Argument-driven dependencies (including those introduced by @export) are sequenced automatically, so @dependsOn is reserved for cases where one field has a side effect that a later field relies on, but neither passes a variable to the other.
The example below shows this case: uploadToFileService does not reference the $batchId exported by batch_create, but it must still run after addNewDocument has registered the document, so the ordering is declared explicitly.
Syntax:
@dependsOn(field: "name")Example:
mutation CreateBatchWithAttachment ($cid: Int,
$batchId: Int = 0,
$fina: String,
$fiby: String,
$tok: String)
{
useCompany(no: $cid) {
# create the batch
batch_create(
values: {
voucherSeriesNo: 1,
valueDate: 20250121
description: "Demo batch"
}
)
{
affectedRows
items {
batchNo @export(as: "batchId")
}
}
# create the voucher
voucher_create(
values: {
batchNo: $batchId
voucherDate: null
voucherType: 21
voucherNo: null
debitAccountNo: 5000
creditAccountNo: 1920
amountDomestic: 500.00
text: "first voucherline"
}
)
{
affectedRows
items {
batchNo
voucherNo
}
# add a document to the batch
voucher_processings {
addNewDocument(
filter: {batchNo: {_eq: $batchId}},
args: {
fileName: $fina,
fileBytes: $fiby
}
)
{
succeeded
}
}
# upload the document to the file service
incomingAccountingDocumentAttachment_processings {
uploadToFileService(
filter: {fileName: {_eq: $fina}},
args: {connectToken: $tok}
) @dependsOn(field: "addNewDocument")
{
succeeded
}
}
}
}References
You can learn more about the core GraphQL directives from these articles: