Forming calls with GraphQL

Learn how to create and run queries and mutations. All provided examples use the Brikl Admin API.

Authorization with Brikl GraphQL API

To communicate with the GraphQL server and retrieve data from your Brikl store, you'll need to include the required HTTP Headers in every call. The HTTP Headers are the way Brikl knows that a client is authorized to retrieve data from a Brikl store.

The best way to follow this tutorial is to use the GraphQL Playground. Follow the steps in Using the GraphQL Playground to set up the required HTTP Headers and start making API calls to retrieve data from your Brikl store.

Endpoint

All Admin API operations are made on a single GraphQL endpoint, which only accepts POST requests:

https://api.brikl.com/graphql/admin/public

The endpoint remains constant no matter what operation you perform.

Communicating with GraphQL

Unlike REST, where HTTP verbs determine the operation performed, GraphQL only works with POST requests. GraphQL uses POST because every operation is performed by providing a JSON-encoded body.

The exception is the introspection query, which does not provide anybody and therefore is a simple GET request to the endpoint.

GraphQL operations: Query and Mutation

The two types of operations available in the Brikl GraphQL API are queries and mutations.

GraphQL queries retrieve data from the server. Compared to REST, GraphQL queries operate like GET requests. 

GraphQL mutations change data on the server and fetch the changed data in a single operation. Mutations are analogous to performing HTTP verbs such as POST, PATCH, and DELETE. The mutation name determines which modification is executed.

Queries and mutations are similar, but there are a few differences. Let's explore each type of operation individually.

The Query operation

GraphQL queries return data from the server. The beauty of queries is that they return only the data you specify—nothing more, nothing less.

To form a query, you must specify the query name you wish to use and the fields you want to retrieve. It's important to note that your query must return only scalar values. If a field does not return a scalar, you should specify nested fields until it returns only scalars.

Here is the basic structure of a query:

query {
 queryName {
   # JSON objects to return
 }
}

The "query" keyword is optional. However, it's recommended to use it to distinguish the operation type easily.

For a real-world example, see our Query example using the Admin API article.

The Mutation operation

To form a mutation, you must include:

  1. The mutation keyword. Unlike queries, for mutations, the mutation keyword is required.
  2. The mutation name. The type of modification you want to perform.
  3. Input object. The data you wish to send to the server. Input objects are objects used as arguments. They are passed to the mutation name.
  4. Payload object. The fields you want to retrieve from the server. The payload object for mutations and queries works in the same way.

Here is the basic structure of a mutation:

mutation {
 MutationName(input: {InputObject!}) {
   PayloadObject
 }
}

In the example above:

  1. MutationName is one of the available mutations on the Admin API.
  2. InputObject represents the input object a mutation requires as an argument.
  3. PayloadObject represents the data we want to return from the server.

For a real-world example, see our Mutation example using the Admin API article.

Query example using the Admin API

Let's walk through a query and explain it thoroughly.

The following query retrieves the first five orders of a Brikl shop and returns each order's id, payment status, and total cost:

query {
  orders(first: 5) {
      edges {
          node {
              id
              paymentStatus
              total
          }
      }
  }
}

Explaining the query line by line:

  • query {

    The query keyword tells the GraphQL server we want to retrieve data from the server, not modify it.

  • orders(first: 5) {

    The query we want to execute is orders. The schema indicates orders can receive up to five arguments, but none of them is required. However, as we wish to retrieve only the first five orders, we must specify the first argument. 

    Visit the API reference for detailed information about the query orders and its arguments.

  • edges {

    The orders query returns a connection named OrderConnection. To retrieve data from a connection, we have to access the node via edges.

  • node {

    Here we retrieve the node at the end of the edge. According to the OrderConnection documentation, the node at the end of the OrderConnection type is an Order object.

    Looking at the Order object documentation, we can specify the fields we want to return:

  •  id
    paymentStatus
    total
    }

In our example, we return the id, paymentStatus, and total fields from each of the five orders. Here's an example of a response our query might get from the server:

{

   "data": {
       "orders": {
           "edges": [
               {
                   "node": {
                       "id": "7a792bc7-6de2-4d2c-8024-b94caabbc637",
                       "paymentStatus": "PAID",
                       "total": 12.09
                    }

               },
                {

                   "node": {
                       "id": "14e06e00-bb1e-477d-99b2-9dfd69acab9e",
                       "paymentStatus": "PENDING",
                       "total": 15.50
                   }
               },
               {
                   "node": {
                       "id": "5d6fe4d6-0b6c-4933-bcad-ae525b469f22",
                       "paymentStatus": "PAID",
                       "total": 150.25
                   }
               },
               {
                   "node": {
                       "id": "fc43d89c-0ccf-4c40-bdad-886d049f482c",
                       "paymentStatus": "FAILED",
                       "total": 10
                   }
               },
               {
                   "node": {
                       "id": "626bd461-6ed1-43b4-aff9-13dc450881d7",
                       "paymentStatus": "CANCELED",
                       "total": 10
                   }
               }
           ]
       }
   }
}

We recommend you to run with the query above in the GraphQL Playground and play with the fields from the Order object. If you didn't set up your GraphQL Playground yet, refer to Using the GraphQL Playground.

Mutation example using the Admin API

When performing a mutation, we often need to pass arguments that we can only find by performing a query first. The updateOrder mutation is a perfect example to illustrate this.

The updateOrder documentation tells us that it requires an input object whose type is UpdateOrderInput. This input object has five fields:

  • comment (String)
  • orderId (ID!)
  • shippingStatus (ShippingStatusEnum)
  • paymentStatus (OrderPaymentStatusEnum)
  • isHiddenFromUsers (Boolean)

The ! indicates that orderId is the only required field. And that makes sense: how could we update a particular order without knowing its ID? 

In order to obtain the ID of a particular order that we want to update, we need to perform a query:

query GetOrdersID {
  orders(first: 5) {
      edges {
          node {
              id
          }
      }
  }
}

The query above is pretty much the same we used before, with two differences:

  1. We are naming it GetOrdersID
  2. It asks for only one field in the Order object: id.

When we run the query, we get the id of the first five orders in a Brikl shop. We'll pass one of the returned IDs as the orderId in the updateOrder mutation. Here's how our mutation must be formed:

mutation UpdateOrderStatus {
 updateOrder(input: {
   orderId: "66c4a31e-39a4-48b1-af00-5f14fd7a37d1",
   comment: "Order paid. Package shipped.",
   shippingStatus: SHIPPED,
   paymentStatus: PAID,
   isHiddenFromUsers: false
 }) {
   order {
       comment
       shippingStatus
       paymentStatus
   }
   orderId
 }
}

The example above performs a simple task: update an order's shipping and payment status and add a comment to it. Also, it returns the newly updated fields comment, shippingStatus, and paymentStatus.

🖐️ Heads up! Before you try to run the mutation above, remember that you'll update your live, production data

Let's breakdown our mutation into parts:

  • mutation UpdateOrderStatus {

    Here we're performing a mutation, and we name it UpdateOrderStatus. Naming a query or a mutation is optional. 

  • updateOrder(input: {
       orderId: "66c4a31e-39a4-48b1-af00-5f14fd7a37d1",
       comment: "Order paid. Package shipped.",
       shippingStatus: SHIPPED,
       paymentStatus: PAID,
       isHiddenFromUsers: false
      }) {

    Let's examine this part:

    • updateOrder is the name of the mutation. See the API reference.
    • input is the required argument key. This will always be input for a mutation.
    • Then we have the required argument value—for mutations, this will always be an input object (hence the curly braces) composed of input fields:
      {
         orderId: "66c4a31e-39a4-48b1-af00-5f14fd7a37d1",
         comment: "Order paid. Package shipped.",
         shippingStatus: SHIPPED,
         paymentStatus: PAID,
         isHiddenFromUsers: false
      }

The orderId field receives one of the IDs our query returned. The comment field is a text string. The fields shippingStatus and paymentStatus are enums, meaning they have a predefined list of possible values. The isHiddenFromUsers has a boolean type, meaning it accepts only a true or false value. You can see the details about each value in the docs for the UpdateOrderInput.

The rest of the call is composed of the payload object. This is where we specify the data we want the server to return after executing our mutation:

  • order {
    comment
       shippingStatus
       paymentStatus
    }
    orderId

When we look at the docs for the updateOrder, we can see that it returns an OrderMutationOutput object, which has two fields: order and orderId.

The orderId field returns the same ID we have passed to the mutation as an argument. The order field is our well-known order object, already explored in the section Query example using the Admin API. In this case, we want the server to return only three fields: comment, shippingStatus, and paymentStatus.

Here's a sample response we can get when we run the mutation:

{
   "data": {
       "updateOrder": {
           "order": {
               "comment": "Order paid. Package shipped.",
               "id": "e97cebe4-72a8-4d5c-a3f4-90095cefc1ce",
               "shippingStatus": "SHIPPED",
               "paymentStatus": "PAID"
           },
           "orderId": "66c4a31e-39a4-48b1-af00-5f14fd7a37d1"
       }
   }
}

You probably noted that the syntax could get cumbersome when we pass multiple fields in an input object. To make our mutation easier to read and understand, we can move the input object fields into a variable. Here's how you could rewrite the mutation using a variable:

mutation UpdateOrderStatus($myVar: UpdateOrderInput!) {
 updateOrder(input: $myVar) {
   order {
       comment
       shippingStatus
       paymentStatus
   }
   orderId
 }
}

variables {
 "myVar": {
  "comment": "Order paid. Package shipped.",
  "orderId": "66c4a31e-39a4-48b1-af00-5f14fd7a37d1",
  "shippingStatus": "SHIPPED",
  "paymentStatus": "PAID",
  "isHiddenFromUsers": false
 }
}

Note: If you're using the GraphQL Playground, make sure to enter variables in the variable pane, and do not include the word "variables" before the JSON object. See Using the variable pane.

That's it! We hope the examples we explored might have taught you everything you need to start playing with the queries and mutations from the Brikl Admin API.

What's next?

Despite this extended tutorial, we just scratched the surface of GraphQL. A good next step would be to explore the Admin API reference and try to form your queries and mutations using the GraphQL Playground. If you still didn't set up your playground, visit Using the GraphQL Playground for a helpful tutorial.

If you're eager to learn about other GraphQL features, here are some places to look next: