Skip to content
Developer home
X3

Fast track to GraphQL

  Less than to read

Okay, let’s talk GraphQL!

Queries

We’ll start with a simple query, and get a list of business partners with code and isActive details.

{
  xtremX3BusinessPartners {
    businessPartner {
      query {
        edges {
          node {
            code
            isActive
          }
        }
      }
    }
  }
}

Operation Names

Let’s give our query a name.

query MyNamedQuery {
  xtremX3BusinessPartners {
    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 {
  xtremX3BusinessPartners {
    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 {
  xtremX3BusinessPartners {
    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 {
  xtremX3BusinessPartners {
    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 {
  xtremX3BusinessPartners {
    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 {
  xtremX3BusinessPartners {
    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 {
  xtremX3BusinessPartners {
    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.