The repo with this code can be found HERE
I’m working on sourcing and combining data from Shopify Storefront and GraphQL Admin APIs into Gatsby. For sourcing Storefront API I use gatsby-source-shopify, though I wasn’t able to find source plugin for Shopify Admin API and ended up using gatsby-source-graphql
.
I have created a private Shopify app and granted all permissions and was able to fetch data using curl example from Shopify GraphQL Admin API documentation.
curl -X POST
"https://shop-name.myshopify.com/admin/api/2019-04/graphql.json"
-H "Content-Type: application/graphql"
-H "X-Shopify-Access-Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
-d '
{
shop {
name
}
}
'
Output:
{"data":{"shop":{"name":"Shop Name"}},"extensions":{"cost":{"requestedQueryCost":1,"actualQueryCost":1,"throttleStatus":{"maximumAvailable":1000.0,"currentlyAvailable":999,"restoreRate":50.0}}}}
Error message:
success open and validate gatsby-configs — 0.007 s
success load plugins — 0.345 s
success onPreInit — 0.005 s
success initialize cache — 0.015 s
success copy gatsby files — 0.068 s
success onPreBootstrap — 0.006 s
error Plugin gatsby-source-graphql returned an error
Error: Parse error on "operationName" (STRING) at [1, 2]
gatsby-source-shopify/sandbox starting to fetch data from Shopify
gatsby-source-shopify/sandbox fetched and processed productTypes: 287.590ms
gatsby-source-shopify/sandbox fetched and processed policies: 297.440ms
gatsby-source-shopify/sandbox fetched and processed blogs: 302.418ms
gatsby-source-shopify/sandbox fetched and processed articles: 344.917ms
gatsby-source-shopify/sandbox fetched and processed collections: 8603.841ms
gatsby-source-shopify/sandbox fetched and processed products: 20362.561ms
gatsby-source-shopify/sandbox finished fetching data from Shopify: 20369.525ms
warning The gatsby-source-graphql plugin has generated no Gatsby nodes. Do you need it?
success source and transform nodes — 21.169 s
warning Multiple node fields resolve to the same GraphQL field `ShopifyArticle.blog` - [`blog`, `blog___NODE`]. Gatsby will use `blog___NODE`.
warning Multiple node fields resolve to the same GraphQL field `ShopifyCollection.products` - [`products`, `products___NODE`]. Gatsby will use `products___NODE`.
warning Multiple node fields resolve to the same GraphQL field `ShopifyProduct.options` - [`options`, `options___NODE`]. Gatsby will use `options___NODE`.
warning Multiple node fields resolve to the same GraphQL field `ShopifyProduct.variants` - [`variants`, `variants___NODE`]. Gatsby will use `variants___NODE`.
success building schema — 0.283 s
success createPages — 0.000 s
success createPagesStatefully — 0.042 s
success onPreExtractQueries — 0.005 s
success update schema — 0.019 s
success extract queries from components — 0.098 s
success run static queries — 0.021 s — 2/2 96.96 queries/second
success run page queries — 0.014 s — 4/4 301.32 queries/second
success write out page data — 0.012 s
success write out redirect data — 0.001 s
success Build manifest and related icons — 0.104 s
success onPostBootstrap — 0.106 s
info bootstrap finished - 23.946 s
WARNING Compiled with 1 warnings 6:04:43 PM
Module Warning (from ./node_modules/eslint-loader/index.js):
/Users/skok/dev/gatsby-shopify-starter/src/components/collections.js
2:10 warning 'useStaticQuery' is defined but never used no-unused-vars
2:26 warning 'graphql' is defined but never used no-unused-vars
✖ 2 problems (0 errors, 2 warnings)
You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.
You can now view gatsby-shopify in the browser.
http://localhost:8000/
View GraphiQL, an in-browser IDE, to explore your site's data and schema
http://localhost:8000/___graphql
Note that the development build is not optimized.
To create a production build, use npm run build
warning ⚠ 「wdm」:
info ℹ 「wdm」: Compiled with warnings.
WAIT Compiling... 6:04:43 PM
info ℹ 「wdm」: Compiling...
WARNING Compiled with 1 warnings 6:04:43 PM
Module Warning (from ./node_modules/eslint-loader/index.js):
/Users/skok/dev/gatsby-shopify-starter/src/components/collections.js
2:10 warning 'useStaticQuery' is defined but never used no-unused-vars
2:26 warning 'graphql' is defined but never used no-unused-vars
✖ 2 problems (0 errors, 2 warnings)
You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.
warning ⚠ 「wdm」:
info ℹ 「wdm」: Compiled with warnings.
gatsby-config.js
:
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`
});
module.exports = {
siteMetadata: {
title: `Gatsby Shopify`,
description: `Gatsby Shopify Starter.`,
author: `@iamskok`,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: "gatsby-source-graphql",
options: {
// This type will contain remote schema Query type
typeName: "ShopifyAdmin",
// This is field under which it's accessible
fieldName: "admin",
// Url to query from
url: `https://${process.env.SHOP_NAME}.myshopify.com/admin/api/2019-04/graphql.json`,
headers: {
// Learn about environment variables: https://gatsby.dev/env-vars
'X-Shopify-Access-Token': `${process.env.ADMIN_PASSWORD}`,
'Content-Type': 'application/graphql'
},
fetchOptions: {
method: 'POST'
},
refetchInterval: 60
},
},
{
resolve: `gatsby-source-shopify`,
options: {
// The domain name of your Shopify shop. This is required.
// Example: 'gatsby-source-shopify-test-shop' if your Shopify address is
// 'gatsby-source-shopify-test-shop.myshopify.com'.
shopName: process.env.SHOP_NAME,
// An API access token to your Shopify shop. This is required.
// You can generate an access token in the "Manage private apps" section
// of your shop's Apps settings. In the Storefront API section, be sure
// to select "Allow this app to access your storefront data using the
// Storefront API".
// See: https://help.shopify.com/api/custom-storefronts/storefront-api/getting-started#authentication
accessToken: process.env.STOREFRONT_ACCESS_TOKEN,
// Set verbose to true to display a verbose output on `npm run develop`
// or `npm run build`. This prints which nodes are being fetched and how
// much time was required to fetch and process the data.
// Defaults to true.
verbose: true,
},
},
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
},
},
],
}
./src/collections.js
:
import React from 'react'
import { useStaticQuery, graphql } from 'gatsby'
const Collections = () => {
const storefrontData = useStaticQuery(
graphql`
query {
allShopifyCollection {
edges {
node {
id
description
descriptionHtml
handle
image {
altText
id
src
localFile {
childImageSharp {
fluid(maxWidth: 910) {
...GatsbyImageSharpFluid_withWebp_tracedSVG
}
}
}
}
products {
id
handle
title
}
title
updatedAt
}
}
}
}
`
)
const adminData = useStaticQuery(
graphql`
query {
admin {
shop {
name
}
}
}
`
)
console.log('storefront data:', JSON.stringify(storefrontData));
console.log('admin data:', JSON.stringify(adminData));
return (
<div className="collections">
<h2>Collections</h2>
</div>
)
}
export default Collections
index.js
:
import React from 'react'
import Layout from '../components/layout'
import Collections from '../components/collections'
const IndexPage = () => (
<Layout>
<h1>Shopify</h1>
<Collections />
</Layout>
)
export default IndexPage
package.json
:
{
"name": "gatsby-shopify",
"private": true,
"description": "Gatsby Shopify Starter",
"version": "0.1.0",
"author": "Vladimir Skok <[email protected]>",
"dependencies": {
"gatsby": "^2.4.2",
"gatsby-image": "^2.0.41",
"gatsby-plugin-manifest": "^2.1.1",
"gatsby-plugin-offline": "^2.1.0",
"gatsby-plugin-react-helmet": "^3.0.12",
"gatsby-plugin-sharp": "^2.0.36",
"gatsby-source-filesystem": "^2.0.33",
"gatsby-source-graphql": "^2.0.18",
"gatsby-source-shopify": "^2.0.28",
"gatsby-transformer-sharp": "^2.1.19",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-helmet": "^5.2.1"
},
"devDependencies": {
"prettier": "^1.17.0"
},
"keywords": [
"gatsby"
],
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write src/**/*.{js,jsx}",
"start": "npm run develop",
"serve": "gatsby serve",
"test": "echo "Write tests! -> https://gatsby.dev/unit-testing""
},
"repository": {
"type": "git",
"url": "https://github.com/iamskok/gatsby-shopify-starter"
},
"bugs": {
"url": "https://github.com/iamskok/gatsby-shopify-starter/issues"
}
}
The expected result is to make a successful GraphQL query to Shopify Admin API. The actual result is server error with 400
status code.
2
Answers
You have a few issues here.
First you need to pass
X-Shopify-Storefront-Access-Token
notX-Shopify-Access-Token
. (if you are really using a private app )
Then you need to request
/api/2019-04/graphql
not/admin/api/2019-04/graphql.json"
.Please refer to this doc: https://help.shopify.com/en/api/custom-storefronts/storefront-api/getting-started#accessing-the-storefront-api-graphql-endpoint
Your
gatsby-source-graphql
setting is different than thecurl
command in the following seting:POST
HTTP MethodContent-Type: application/graphql
headerIn order to match the curl command, you could try the setting below: