Can't Fetch Graphql Admin API with Koa-shopify-graphql-proxy

navo17
Shopify Partner
6 0 3

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?

  1. Query?
  2. How the fetch is composed? Or should I use some other fetch like isomorphic?
  3. My app is a sales channel app, is there something related to that?

 

Appreciate any help here guys.

 

banned
Replies 7 (7)

asibilia
Tourist
5 0 3

If you end up figuring it out please share your results. I'm also struggling with this. Cheers

Alex
Shopify Staff
1561 81 341

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

asibilia
Tourist
5 0 3

 

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)

gql`QUERY`gql`QUERY``QUERY``QUERY` 

Alex
Shopify Staff
1561 81 341

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

jasontll
Visitor
1 0 1

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)
});
}
};

 

asdfasdf
Visitor
1 0 3

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 🙂

PublicApps
Shopify Partner
146 5 34

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.