Fast track to GraphQL
Less than to read
Okay, let’s talk GraphQL!
- Queries
- Operation Names
- Filtering
- Sorting
- Pagination
- Aliases
- Fragments
- Variables
- Directives
- Aggregation
- Mutations
Queries
We’ll start with a simple query, and get a list of business partners with code and isActive details.
{
xtremX3MasterData {
businessPartner {
query {
edges {
node {
code
isActive
}
}
}
}
}
}
Operation Names
Let’s give our query a name.
query MyNamedQuery {
xtremX3MasterData {
businessPartner {
query {
edges {
node {
code
isActive
}
}
}
}
}
}
Filtering
With the ability to pass arguments to fields for filtering results, things get much more interesting.
query MyNamedQuery {
xtremX3MasterData {
businessPartner {
query(filter : "{code :'AE003'}") {
edges {
node {
code
isActive
}
}
}
}
}
}
If the filter is based on an identifier, we can use read operation for better performance.
query MyNamedQuery {
xtremX3MasterData {
businessPartner {
read(_id: "AE003") {
isActive
}
}
}
}
Sorting
Now let’s sort the result (1 or +1 stands for ascending order, and -1 is for descending order).
query MyNamedQuery {
xtremX3MasterData {
businessPartner {
query(orderBy: "{code:-1}") {
edges {
node {
code
isActive
}
}
}
}
}
}
Pagination
If the result is too long, you can limit the length and manage pagination.
query MyNamedQuery {
xtremX3MasterData {
businessPartner {
query(first: 5) {
edges {
node {
code
isActive
}
}
pageInfo {
endCursor
hasNextPage
startCursor
hasPreviousPage
}
}
}
}
}
We’ll get the next 5 results in the list using ‘after’.
query MyNamedQuery {
xtremX3MasterData {
businessPartner {
query(first: 5, after : "[\"AE020\"]#73") {
edges {
node {
code
isActive
}
}
pageInfo {
endCursor
hasNextPage
startCursor
hasPreviousPage
}
}
}
}
}
‘last’ and ‘before’ can be used to return data in the opposite direction.
query MyNamedQuery {
xtremX3MasterData {
businessPartner {
query(last: 5, before : "[\"AO021\"]#10") {
edges {
node {
code
isActive
}
}
pageInfo {
endCursor
hasNextPage
startCursor
hasPreviousPage
}
}
}
}
}
Aliases
You can’t query the same field with different arguments directly, but that’s where aliases come in - they enable you to rename field results.
query MyNamedQueryWithAliases {
xtremX3Products {
product {
subcoProduct: query (filter: "{productCategory: 'SUBCO'}", first: 5, orderBy: "{ code: -1 }") {
edges {
node {
code
accountingCode
description1
localizedDescription1
productCategory{
code
}
}
}
}
sfiniProduct: query(filter: "{productCategory: 'SFINI'}", first: 5, orderBy: "{ code: -1 }") {
edges {
node {
code
accountingCode
description1
localizedDescription1
productCategory{
code
}
}
}
}
}
}
}
Fragments
If you want to compare field results, GraphQL comes with reusable units called fragments.
query MyNamedQueryWithAliasesAndFragment {
xtremX3Products {
product {
leftComparison: query(filter: "{productCategory: 'SUBCO'}") {
...comparisonFields
}
rightComparison: query(filter: "{productCategory: 'SFINI'}") {
...comparisonFields
}
}
}
}
fragment comparisonFields on Product_Query {
edges {
node {
code
productCategory {
code
}
accountingCode
description1
localizedDescription1
}
}
}
Variables
Should you need to repeat the same query with a different filter, use variables. When you work with variables, you’ll need to :
- Replace the static value in the query with $variableName
- Declare $variableName as one of the variables accepted by the query
- Pass variableName value in the separate, transport-specific (usually JSON) variables dictionary
# If you need to use another value than the default value of
# $productFilter, just put it in the Query Variables zone, e.g :
# {"productFilter" : "{productCategory: 'SUBCO'}"}
query ProductsInCategory($productFilter: String = "{productCategory: 'SFINI'}") {
xtremX3Products {
product {
query(filter: $productFilter, first: 5, orderBy: "{ code: 1 }") {
edges {
node {
code
productCategory {
code
}
accountingCode
description1
localizedDescription1
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
}
Directives
You may need to change the structure and shape of your queries dynamically, for example - if your App has 2 views: simple and detailed.
There are 2 keywords which can solve this problem…. @include and @skip:
The following example, returns a list of orders and their lines:
query MyNamedQuery($withLines: Boolean!) {
xtremX3Purchasing {
purchaseOrder {
query {
totalCount
edges {
node {
id
purchaseSite {
name
}
purchaseOrderQuantityLines @include(if: $withLines) {
query {
edges {
node {
product {
code
description1
}
quantityInOrderUnitOrdered
}
}
}
}
}
}
}
}
}
}
For a simple view, pass the following variables:
{"withLines": false}
For a detailed view, pass these variables:
{"withLines": true}
If you replace @include with @skip, switch the variables value (false and true) to achieve the same result.
Aggregation
Select purchase orders that have at least one line with an ordered quantity greater than 1000 and display only the lines in the order that have quantities between 100 and 8000.
query MyNamedQuery {
xtremX3Purchasing {
# Select purchase orders that have at least one line with an ordered quantity greater than 1000
purchaseOrder {
query(filter: "{purchaseOrderQuantityLines:{_atLeast:1,quantityInOrderUnitOrdered:{_gt:1000}}}") {
totalCount
edges {
node {
# Display the id and the site name
id
purchaseSite {
name
}
purchaseOrderQuantityLines {
# Display only the lines in the order that have quantities between 100 and 8000
query(filter: "{quantityInOrderUnitOrdered:{_gte:100,_lte:8000}}") {
edges {
node {
product {
code
description1
}
quantityInOrderUnitOrdered
}
}
}
}
}
}
}
}
}
}
Search for product related data using regular expression: compute the minimum and maximum of weight, and the number of different units
{
xtremX3Products {
product {
# On lines wich a description following a regular expression (contains standard)
# compute the minimum and maximum of weight, and the number of different units
readAggregate(filter: "{description1:{_regex:'.*standard.*'}}") {
productWeight {
min
max
}
stockUnit {
code {
distinctCount
}
}
}
# Add in the payload the details of the lines following the selection criterion
query(filter: "{description1:{_regex:'.*standard.*'}}") {
edges {
node {
description1
productWeight
stockUnit{
code
}
}
}
}
}
}
}
Mutations
Last but by no means least, let’s talk ‘mutations’. Our attention thus far has been focussed on data fetching, but any complete data platform needs a way to modify server-side data too.
Let’s create a stock receipt.
# Let's use a mutation to create a stock receipt
mutation {
xtremX3Stock {
miscellaneousReceipt {
create(data:
{
# Header information
stockSite: "AO011",
effectiveDate: "2020-12-30",
# Line details
miscellaneousReceiptLines: [
# First line, product DIS004, quantity 230
{stockSite: "AO011", product: "DIS004", quantityInPackingUnit: "230", packingUnit: "UN",
# Sub-details: 200 in status 1, 30 in status Q
stockDetails: [
{quantityInPackingUnit: "200", packingUnit: "UN", location: "A1C11", status: "A"},
{quantityInPackingUnit: "30", packingUnit: "UN", location: "A1C11", status: "Q"}
]},
# Second line: product DIS008, quantity 158, a unique sub-detail line (status A)
{stockSite: "AO011", product: "DIS008", quantityInPackingUnit: "158", packingUnit: "UN",
stockDetails: [
{quantityInPackingUnit: "158", packingUnit: "UN", location: "A1C12", status: "A"}
]},
# Third line: product CON006, quantity 1, a unique sub-detail line (a serial number)
{stockSite: "AO011", product: "CON006", quantityInPackingUnit: "1", packingUnit: "UN",
stockDetails: [
{quantityInPackingUnit: "1", packingUnit: "UN", serialNumber: "ABC082",
location: "A1C11", status: "A"}
]
} ]})
# If successful, return the id of the receipt and the effective date
{
id
effectiveDate
}
}
}
}
Now you’re talking GraphQL!
See Samples - queries, mutations and more to talk some more.