# GraphQL Queries

Magento exposes a [GraphQL](https://graphql.org/) API, which ScandiPWA builds upon and uses to fetch and mutate data. GraphQL is more flexible than REST, and offers a type checking system.

You might want to [read the GraphQL documentation](https://graphql.org/learn/) to get a full understanding of the language, but we do provide a quick introduction below.

## Introduction to GraphQL

GraphQL queries look like JSON objects without quotes or values, and describe which fields you want to fetch from the server:

```graphql
{
  categoryList {
    name
    children {
      name
      url
      product_count
    }
  }
}
```

In this case, we want to query the `categoryList` field, and fetch its name and children fields. For the children, we want to fetch the name, URL, and product count. It is not clear from the query, but if you were to look at the GraphQl schema, you would know that `children` is actually an array of such objects.

If we make the above request to the GraphQL endpoint on a Magento instance (it's usually `/graphql`), we would get the following JSON response:

```javascript
{
  "data": {
    "categoryList": [
      {
        "name": "Default Category",
        "children": [
          {
            "name": "Audio, Video & Photo Equipment",
            "url": "/audio-video-photo-equipment.html",
            "product_count": 0
          },
          {
            "name": "Home Security & Automation",
            "url": "/home-security-automation.html",
            "product_count": 0
          },
          {
            "name": "Computers, Peripherals & Accessories",
            "url": "/computers-peripherals-accessories.html",
            "product_count": 1
          },
          {
            "name": "Office",
            "url": "/office.html",
            "product_count": 2
          },
          {
            "name": "Telecom & Navigation",
            "url": "/telecom-navigation.html",
            "product_count": 0
          },
          // [...]
        ]
      }
    ]
  }
}
```

{% hint style="info" %}
The `categoryList` query has other fields that we could fetch (such as `id`, `description`), but GraphQL only returns the ones we asked for.
{% endhint %}

## API

### Generating GraphQL Queries

Commonly, when building an application, GraphQL queries are specified in the code as strings, much like the query above. While this method does have its advantages, it is hard to extend - what happens when you want to override a theme and need to fetch one more field from the same query? If queries were hardcoded as strings, you would have to copy and edit the string to create a new query in your theme, which would quickly get hard to maintain. And what about plugins? There would be no easy way to write a plugin that asks for an additional field in some query.

The solution ScandiPWA proposes is to generate queries dynamically. Then, adapting the query to your needs is as easy as using the [Override Mechanism](/developing-with-scandi/override-mechanism/extending-javascript.md) on the query's class.&#x20;

ScandiPWA implements its own library to enable you to generate GraphQL queries and mutations. This is defined in `util/Query`.

#### Field

Represents a [GraphQL field](https://graphql.org/learn/queries/#fields)

| Method                                                                                                                                                                 | Description                                                                                                                                  |                                                                                                                                                                                                                         |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p><code>addField(</code></p><p>  <code>field: Field                                                                                                                   | string</code></p><p><code>) -> this</code></p>                                                                                               | Adds the specified child field to this field as a subfield. The child field must be either an instance of Field, or a string. If a string is specified, this is equivalent to calling `addField(new Field(string))`     |
| <p><code>addFieldList(</code></p><p>  <code>fields:(Field                                                                                                              | string)\[]</code></p><p><code>) -> this</code></p>                                                                                           | Adds the specified list of child fields to this field as subfields. Each item of `fields` must be either an instance of Field, or a string. If a string is specified, this is equivalent to passing `new Field(string)` |
| <p><code>addArgument(</code></p><p>  <code>name: string,</code></p><p>  <code>type: string,</code></p><p>  <code>value: string</code></p><p><code>) -> this</code></p> | Adds an argument called `name` with a value of `value` of type `type` to this field. All three parameters must be strings, and are required. |                                                                                                                                                                                                                         |
| <p><code>setAlias(</code></p><p>  <code>alias: string</code></p><p><code>) -> this</code></p>                                                                          | Aliases the field to the specified alias.                                                                                                    |                                                                                                                                                                                                                         |

#### Fragment

Represents a [GraphQL fragment](https://graphql.org/learn/queries/#fragments). Extends Field, and hence has the same API.

#### Example

```javascript
import { Field, prepareFieldString } from 'Util/Query';

const childrenField = new Field('children')
    .addFieldList([
        'name',
        'url',
        'productCount'
    ]);

const query = new Field('categoryList')
    .addArgument('filter', 'CategoryFilterInput', {})
    .addField('name')
    .addField(childrenField)
    .setAlias('categories');

console.log(prepareFieldString(query));
```

Resulting Query (argument valus are sent separately):

```graphql
categories:categoryList(filter:$filter_1){name,children{name,url,productCount}}
```

### Making Queries

Functions that make requests are defined in `util/Request`. These implement a smart caching mechanism to improve performance and reduce load.

| Function                                                  | Description                                                   |                                                                                                                                                                     |
| --------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p><code>fetchQuery(</code></p><p>  <code>query: Field    | Field\[]</code></p><p><code>) -> Promise\<Request></code></p> | Fetches a query or array of queries, and returns a Promise that resolves when the query successfully completes. If the query fails, so does the Promise.            |
| <p><code>fetchMutation(</code></p><p>  <code>query: Field | Field\[]</code></p><p><code>) -> Promise\<Request></code></p> | Fetches a mutation or array of mutations, and returns a Promise that resolves when the mutation successfully completes. If the mutation fails, so does the Promise. |

### QueryDispatcher

`QueryDispatcher` is a base class for redux dispatchers that can simplify making queries. Dispatchers that need to make queries typically need to make the request, and then handle the resulting data or any errors. `QueryDispatcher` automates this this by implementing a `handleData` function that performs this logic.

A subclass extending `QueryDispatcher` will need to define 3 functions. Once these 3 functions are defined, `handleData` will work automatically as expected.

* `prepareRequest(options, dispatch)`, a function that returns the query that the dispatcher wants to make
* `onSuccess(data, dispatch)`, a function that is called with the response data when the query completes successfully
* `onError(error, dispatch)`, a function that is called on request error

Note that all 3 functions get access to Redux's `dispatch` function in case they need to use it (e.g. to show a notification).

## GraphQL in ScandiPWA

To keep the codebase organized, we don't want the components or redux dispatchers to be responsible for generating queries. Instead, we keep all query-generating code in `query`.

By convention, `query` contains 1 JavaScript file for each group of related queries. For example, the `Cart.query.js` file contains queries relating to querying or mutating the customer's cart. All of these files define classes with one or more functions to generate some query, as well as "private" helper methods (optionally). These classes are exported as singleton instances intended to be used by the rest of the app. For an example, consider the [`Cart.query.js`](https://github.com/scandipwa/scandipwa/blob/master/packages/scandipwa/src/query/Cart.query.js) file:

{% code title="query/Cart.query.js (simplified, annotated)" %}

```javascript
import { isSignedIn } from 'Util/Auth';
import { Field } from 'Util/Query';

/** @namespace Query/Cart */
export class CartQuery {
    // creates a query for getting cart data
    // caller method expected to provide certain arguments
    getCartQuery(quoteId) {
        const query = new Field('getCartForCustomer')
            .addFieldList(this._getCartTotalsFields())
            .setAlias('cartData');

        // since queries are generated dynamically, we can add different
        // arguments based on certain conditions
        if (!isSignedIn()) {
            query.addArgument('guestCartId', 'String', quoteId);
        }

        return query;
    }

    getSaveCartItemMutation(product, quoteId) {
        const mutation = new Field('saveCartItem')
            .addArgument('cartItem', 'CartItemInput!', product)
            .addFieldList(this._getSaveCartItemFields(quoteId));

        if (!isSignedIn()) {
            mutation.addArgument('guestCartId', 'String', quoteId);
        }

        return mutation;
    }

    getRemoveCartItemMutation(item_id, quoteId) {...}

    getApplyCouponMutation(couponCode, quoteId) {...}

    getRemoveCouponMutation(quoteId) {...}

    // [...] helper methods not intended for public use
}

export default new CartQuery();
```

{% endcode %}

When a query generation file is defined, it can be used to make requests in dispatchers as well as component's containers.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.scandipwa.com/structure/building-blocks-summary/constructing-graphql-queries.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
