A space to discuss GraphQL queries, mutations, troubleshooting, throttling, and best practices.
Hey,
I am trying to Fetch product details with the Graphql Admin API from my embedded app when a button click happens.
On my Server I am using Koa-shopify-graphql-proxy as middleware as per this tutorial.
Server.js
const { default: graphQLProxy } = require('@shopify/koa-shopify-graphql-proxy'); const { ApiVersion } = require('@shopify/koa-shopify-graphql-proxy'); app.prepare().then(() => { ... server.use(graphQLProxy({ version: ApiVersion.July19 })); ... }
I am calling fetch as suggested here for client script -> https://github.com/Shopify/quilt/tree/master/packages/koa-shopify-graphql-proxy
As per my understanding, with this I can make a call from client and Koa-shopify-graphql-proxy will handle all the authentication on its end and should return the data.
Component.js
const GET_PRODUCT = gql` query { product (id: "gid://shopify/Product/#######"){ title id description onlineStoreUrl } } `; handleProductSelection = (selectPayload) => { .... fetch('/graphql', {method: 'POST' ,credentials: 'include', body: GET_PRODUCT}) .then(function(response) { return response.json(); }) .then(function(myJson) { console.log(JSON.stringify(myJson)); }); .... }I am getting the following error when I run this.
Component.js: POST https://#####.ngrok.io/graphql 400 (Bad Request) Component.js: {"errors":{"query":"Required parameter missing or invalid"}}
In the docs of Koa-shopify-graphql-proxy they don't write 'method: POST'. If I remove then I get an error that can't send 'body' in GET/HEAD request.
What is the issue here?
Appreciate any help here guys.
If you end up figuring it out please share your results. I'm also struggling with this. Cheers
It looks to me like the body you're setting in your fetch
request needs to instead be a JSON object. Requests to the GraphQL endpoint expect a JSON object with, at minimum, a query
value. Here's what you can try:
fetch('/graphql', {method: 'POST', credentials: 'include', body: {"query": GET_PRODUCT}})
Let me know how that goes.
Cheers.
Alex | Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
Both:
const body = { query: gql` query { shop { id } } ` };
const response = await fetch('graphql', { method: 'POST', credentials: 'include', body: JSON.stringify(body) });
and
const body = { query: ` query { shop { id } } ` };
const response = await fetch('graphql', { method: 'POST', credentials: 'include', body: JSON.stringify(body) });
Return the same error:
{"errors":{"query":"Required parameter missing or invalid"}}
(Network Request Payloads below)
Hmm, ok strange. Would you mind making an issue here?
Cheers.
Alex | Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
You need the content-type: "application/json" header.
Here's a working example
const body = {
query: `query {
shop {
id
}
}`
};
export default {
getShop: async () => {
await fetch("graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify(body)
});
}
};
THIS WAS DESTROYING ME FOREVER.
As soon as I got rid of the koa-bodyparser middleware, it worked.
Digging through the shopify-graphql-proxy.js in my node modules folder:
case 2: if (accessToken == null || shop == null) { ctx.throw(403, 'Unauthorized'); return [2 /*return*/]; } console.log(ctx.request.body, accessToken); return [4 /*yield*/, koa_better_http_proxy_1.default(shop, { https: true, parseReqBody: false, // Setting request header here, not response. That's why we don't use ctx.set() // proxy middleware will grab this request header headers: { 'Content-Type': 'application/json', 'X-Shopify-Access-Token': accessToken, }, proxyReqPathResolver: function () { return exports.GRAPHQL_PATH_PREFIX + "/" + version + "/graphql.json"; }, })(ctx, /* We want this middleware to terminate, not fall through to the next in the chain, but sadly it doesn't support not passing a `next` function. To get around this we just pass our own dummy `next` that resolves immediately. */ noop)];
Ignore the console.log(ctx.request.body, accessToken), that was something I added to the file.
The parseReqBody: false in the koa_better_http_proxy_1.default settings was the hint that I needed to disable the koa-bodyparser.
This is the query I used to finally get a 200 response and returned data in one of my served HTML files (I'm using Koa and serving HTML with the koa-ejs templating engine, no React):
const scripts = (async function getScripts(){ const GET_SCRIPTS = JSON.stringify({ query: `query scriptTags { scriptTags(first: 100){ edges { node { src id } cursor } pageInfo { hasNextPage } } }` }); console.log(GET_SCRIPTS); let res = await fetch('/graphql', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: GET_SCRIPTS, }); let json = await res.json(); console.log(json); return json; })(); console.log(scripts);
I hope this helps 🙂
I encountered this scenario as well.
If you use a body parser, e.g. something like:
const bodyParser = require('koa-bodyparser');
...
server.use(bodyParser());
Then make sure the request to /graphql gets proxied with the unparsed body. Do something like:
server.use(async (ctx, next) => {
if (ctx.path === '/graphql') {
return await next();
}
await bodyParser()(ctx, next);
});
instead.
Public Apps | Theme customization & App development
- Was my reply useful? Like it to let me know!
- Did I answer your question? Please mark as Accepted Solution.
- Need more help? Contact us.