Skip to content

Latest commit

 

History

History

graphql-client

GraphQL Client

The GraphQL Client can be used to interact with any Shopify's GraphQL APIs. Client users are expected to provide the full API URL and necessary headers.

Getting Started

Using your preferred package manager, install this package in a project:

yarn add @shopify/graphql-client
npm install @shopify/graphql-client --s
pnpm add @shopify/graphql-client

CDN

The UMD builds of each release version are available via the unpkg CDN

// The minified `v0.9.3` version of the GraphQL API Client
<script src="https://unpkg.com/@shopify/[email protected]/dist/umd/graphql-client.min.js"></script>

<script>
const client = ShopifyGraphQLClient.createGraphQLClient({...});
</script>

Client initialization

import {createGraphQLClient} from '@shopify/graphql-client';

const client = createGraphQLClient({
  url: 'http://your-shop-name.myshopify.com/api/2023-10/graphql.json',
  headers: {
    'Content-Type': 'application/json',
    'X-Shopify-Storefront-Access-Token': 'public-token',
  },
  retries: 1
});

Create a server enabled client using a custom Fetch API

In order to use the client within a server, a server enabled JS Fetch API will need to be provided to the client at initialization. By default, the client uses window.fetch for network requests.

import {createGraphQLClient} from '@shopify/graphql-client';
import {fetch as nodeFetch} from 'node-fetch';

const client = createGraphQLClient({
  url: 'http://your-shop-name.myshopify.com/api/2023-10/graphql.json',
  headers: {
    'Content-Type': 'application/json',
    'X-Shopify-Storefront-Access-Token': 'public-token',
  },
  customFetchApi: nodeFetch
});

createGraphQLClient() parameters

Property Type Description
url string The GraphQL API URL
headers Record<string, string | string[]> Headers to be included in requests
retries? number The number of HTTP request retries if the request was abandoned or the server responded with a Too Many Requests (429) or Service Unavailable (503) response. Default value is 0. Maximum value is 3.
customFetchApi? (url: string, init?: {method?: string, headers?: HeaderInit, body?: string}) => Promise<Response> A replacement fetch function that will be used in all client network requests. By default, the client uses window.fetch().
logger? (logContent: HTTPResponseLog|HTTPRetryLog) => void A logger function that accepts log content objects. This logger will be called in certain conditions with contextual information.

Client properties

Property Type Description
config {url: string, headers: Record<string, string | string[]>, retries: number} Configuration for the client
fetch (operation: string, options?: RequestOptions) => Promise<Response> Fetches data from the GraphQL API using the provided GQL operation string and RequestOptions object and returns the network response
request <TData>(operation: string, options?: RequestOptions) => Promise<ClientResponse<TData>> Fetches data from the GraphQL API using the provided GQL operation string and RequestOptions object and returns a normalized response object
requestStream <TData>(operation: string, options?: RequestOptions) => Promise <AsyncIterator<ClientStreamResponse<TData>>> Fetches GQL operations that can result in a streamed response from the API (eg. Storefront API's @defer directive). The function returns an async iterator and the iterator will return normalized stream response objects as data becomes available through the stream.

RequestOptions properties

Name Type Description
variables? Record<string, any> Variable values needed in the graphQL operation
url? string Alternative request API URL
headers? Record<string, string | string[]> Additional and/or replacement headers to be used in the request
retries? number Alternative number of retries for the request. Retries only occur for requests that were abandoned or if the server responds with a Too Many Request (429) or Service Unavailable (503) response. Minimum value is 0 and maximum value is 3.
signal? AbortSignal If this option is set, the request can be canceled by calling abort() on the corresponding AbortController.

ClientResponse<TData>

Name Type Description
data? TData | any Data returned from the GraphQL API. If TData was provided to the function, the return type is TData, else it returns type any.
errors? ResponseErrors Errors object that contains any API or network errors that occured while fetching the data from the API. It does not include any UserErrors.
extensions? Record<string, any> Additional information on the GraphQL response data and context. It can include the context object that contains the context settings used to generate the returned API response.

ClientStreamResponse<TData>

Name Type Description
data? TData | any Currently available data returned from the GraphQL API. If TData was provided to the function, the return type is TData, else it returns type any.
errors? ResponseErrors Errors object that contains any API or network errors that occured while fetching the data from the API. It does not include any UserErrors.
extensions? Record<string, any> Additional information on the GraphQL response data and context. It can include the context object that contains the context settings used to generate the returned API response.
hasNext boolean Flag to indicate whether the response stream has more incoming data

ResponseErrors

Name Type Description
networkStatusCode? number HTTP response status code
message? string The provided error message
graphQLErrors? any[] The GraphQL API errors returned by the server
response? Response The raw response object from the network fetch call

Usage examples

Query for a product

const productQuery = `
  query ProductQuery($handle: String) {
    product(handle: $handle) {
      id
      title
      handle
    }
  }
`;

const {data, errors, extensions} = await client.request(productQuery, {
  variables: {
    handle: 'sample-product',
  },
});

Query for product info using the @defer directive

const productQuery = `
  query ProductQuery($handle: String) {
    product(handle: $handle) {
      id
      handle
      ... @defer(label: "deferredFields") {
        title
        description
      }
    }
  }
`;

const responseStream = await client.requestStream(productQuery, {
  variables: {handle: 'sample-product'},
});

// await available data from the async iterator
for await (const response of responseStream) {
  const {data, errors, extensions, hasNext} = response;
}

Add additional custom headers to the API request

const productQuery = `
  query ProductQuery($handle: String) {
    product(handle: $handle) {
      id
      title
      handle
    }
  }
`;

const {data, errors, extensions} = await client.request(productQuery, {
  variables: {
    handle: 'sample-product',
  },
  headers: {
    'Shopify-Storefront-Id': 'shop-id',
  },
});

Use an updated API URL in the API request

const productQuery = `
  query ProductQuery($handle: String) {
    product(handle: $handle) {
      id
      title
      handle
    }
  }
`;

const {data, errors, extensions} = await client.request(productQuery, {
  variables: {
    handle: 'sample-product',
  },
  url: 'http://your-shop-name.myshopify.com/api/unstable/graphql.json',
});

Set a custom retries value in the API request

const shopQuery = `
  query ShopQuery {
    shop {
      name
      id
    }
  }
`;

// Will retry the HTTP request to the server 2 times if the requests were abandoned or the server responded with a 429 or 503 error
const {data, errors, extensions} = await client.request(shopQuery, {
  retries: 2,
});

Provide GQL query type to client.request() and client.requestStream()

import {print} from 'graphql/language';

// GQL operation types are usually auto generated during the application build
import {CollectionQuery, CollectionDeferredQuery} from 'types/appTypes';
import collectionQuery from './collectionQuery.graphql';
import collectionDeferredQuery from './collectionDeferredQuery.graphql';

const {data, errors, extensions} = await client.request<CollectionQuery>(
  print(collectionQuery),
  {
    variables: {
      handle: 'sample-collection',
    },
  }
);

const responseStream = await client.requestStream<CollectionDeferredQuery>(
  print(collectionDeferredQuery),
  {
    variables: {handle: 'sample-collection'},
  }
);

Using client.fetch() to get API data

const shopQuery = `
  query shop {
    shop {
      name
      id
    }
  }
`;

const response = await client.fetch(shopQuery);

if (response.ok) {
  const {errors, data, extensions} = await response.json();
}

Log Content Types

HTTPResponseLog

This log content is sent to the logger whenever a HTTP response is received by the client.

Property Type Description
type LogType['HTTP-Response'] The type of log content. Is always set to HTTP-Response
content {requestParams: [url, init?], response: Response} Contextual data regarding the request and received response

HTTPRetryLog

This log content is sent to the logger whenever the client attempts to retry HTTP requests.

Property Type Description
type LogType['HTTP-Retry'] The type of log content. Is always set to HTTP-Retry
content {requestParams: [url, init?], lastResponse?: Response, retryAttempt: number, maxRetries: number} Contextual data regarding the upcoming retry attempt.

requestParams: parameters used in the request
lastResponse: previous response
retryAttempt: the current retry attempt count
maxRetries: the maximum number of retries

RequestParams

Property Type Description
url string Requested URL
init? {method?: string, headers?: HeaderInit, body?: string} The request information