@dotdev/shopify-client
v0.1.18
Published
Typed API client for the Shopify Admin and Storefront GraphQL APIs
Downloads
713
Maintainers
Keywords
Readme
Shopify Client
This package combines graphql-codegen and graphql-request to provide a fully typed Shopify client for the Shopify GraphQL Admin API and the Shopify Storefront API (coming soon).
- Built in Shopify authentication headers
- Fully typed using your own queries, mutations and fragments
- Rate limit error handling with backoff and retry (coming soon)
- Round robin credential cycling for spreading rate limits across multiple keys
Motivation
Shopify offers two GrahpQL APIs: the Storefront API and the GraphQL Admin API. These APIs can be accessed using any GraphQL compatible client or even plain old fetch. However, despite GraphQL being inherently strongly typed, none of these tools give us typescript types without extensive configuration.
For example, if you wanted to use the productCreate mutation, you need to first reference the documentation page or a GraphQL introspection tool to find out what the input and output looks like. Then you would probably use graphql-tag to define your mutation which you then pass into your GraphQL client along with your mutation arguments.
The problem with this is at no stage has your mutation or arguments been type checked against the actual Shopify API. This includes when you're executing the mutation in your app logic. The only time you find out something isn't right, is when you run the query during testing and Shopify returns an error.
This problem is exacerbated when you need to migrate to a newer API version which might include changes to available fields and required mutation arguments. The only way to test these would be to run them, which is usually left to production.
Introducing type safety
By applying types to our queries and mutations and most importantly validating these types against the real Shopify API, we can be sure that the execution will work in production.
This was previously attempted with the @dotdev/shopify package. The idea was that rather than calling GraphQL directly, we would instead define a class with methods like createProduct
which had the input and response already typed out. The problem with this was that the queries themselves were locked into the package, making it inflexible if you wanted to update something. We were constantly adding new methods and udpating types to match the latest API.
Ultimately, because it was so annoying to use, everyone stopped using it and went back to direct GraphQL queries.
Type generation
Building on the above, we still want our queries and mutations to be typed, but we want our queries and mutations to remain flexible, such that we can update them specifically for our app. We also want them to automatically update when we update the Shopify API version (and fail if they no longer match) without making arduous updates to this package.
To tackle this, this package interacts with a special auto-generated type file, generated using graphql-codegen. To generate this file, you define all the queries, mutations and fragments you want to use within your app, using .graphql
files. Once defined, you run a generation command which reads in your files, connects to the actual Shopify API to fetch the current types, and generates a special typescript file which is consumed by this package.
With this methodology, this package actually contains no types at all and has no dependency on a specific API version. However, you can still call shopifyAdmin.client.createProduct
as expected with full type safety.
Installation
npm i @dotdev/shopify-client --save
Usage
When you have completed the setup section below to generate your GraphQL types, you will instantiate the ShopifyAdmin
class using your generated type file.
import { ShopifyAdmin } from "@dotdev/shopify-client";
// see setup section for how to generate this
import { getSdk } from "./generated/graphql";
const shopify = new ShopifyAdmin({
getSdk,
// or use an array to use key cycling
credentials: {
password: "supersecret",
},
});
// product will have the appropriate type as defined
// by your mutation query attributes
const product = await shopify.client.createProduct({
input: {
// this will throw a type error, as Shopify
// expects title to be a string
title: true,
},
});
Setup
This library does not contain any Shopify types. To populate .client
with the queries and mutations utilised by your app, you need to provide a special getSdk
parameter in the constructor. This parameter is fetched from an auto-generated typescript file which contains the GraphQL queries, mutations and fragments used by your app alongside the types returned and expected to be received by your target Shopify API version.
Installaing @graphql-codegen
Within your project, run the following to install the necessary development dependencies to generate your types.
npm i @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-generic-sdk @graphql-codegen/typescript-operations --save-dev
Defining your queries, mutations and fragments
Choose a directory in your project where you will define the GraphQL queries, mutations and fragments to be used by your application. You might choose ./graphql
but it can be anywhere you like.
Within this directory, create a separate .graphql
file each query, mutation and fragment you want to use. For example, if wanted to use the productCreate
mutation, you might create a file called productCreate.graphql
with the following contents.
mutation productCreate($input: ProductInput!) {
productCreate(input: $input) {
product {
...productFragment
}
userErrors {
field
message
}
}
}
Notice that in the above mutation, we are referencing a fragment called productFragment
. You would define this fragment in it's own file called productFragment.graphql
.
fragment productFragment on Product {
id
handle
title
...other properties
}
Each of your mutations and queries must be named as this is what names the method applied to the Shopify client. For example, the mutation above is called productCreate
which means it will be available at shopify.client.productCreate()
. This means we can use multiple versions of the same Shopify mutation or query, but for different purposes.
Create a codegen.json file
In the root of your project, create a new file called codegen.json
with the following contents. This file is what configures graphql-codegen and points it at your GraphQL files.
The shop and password included in the file below is a restricted API key within a DotDev sandbox store. You are free to use the token below and commit it to your project. This is where the GraphQL schema will be downloaded from and Shopify requires an access token for all requests, even just to fetch the schema.
Note the API version within the Shopify URL. If you wish to target a different API version, simply update it in the URL and schema will be pulled from there instead.
{
"overwrite": true,
"schema": {
"https://dotdev-plus-sandbox.myshopify.com/admin/api/2021-01/graphql.json": {
"headers": {
"X-Shopify-Access-Token": "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"
}
}
},
"documents": "graphql/**/*.graphql",
"generates": {
"generated/graphql.ts": {
"plugins": [
"typescript",
"typescript-operations",
"typescript-generic-sdk"
]
}
}
}
Add the generate command to your package scripts
Each time you make changes to your GraphQL files or upgrade the API version, you will need to regenerate your types to get the methods added to the SDK. Since this is something you might do regularly, you will want to add the command as a package.json script.
"scripts": {
"generate-shopify-types": "graphql-codegen --config codegen.json"
}
Generate your types file
To generate your types file, run the command below. This will scan your GraphQL directory for the queries and mutations you're using in your app, connect to the Shopify API to get the schema for the current version, and finally generate a typescript file into generated/graphql.ts
.
npm run generate-shopify-types
Begin using the client
Now that you have completed setup, follow the usage section to begin using your new fully typed Shopify client.