Problem Querying REST API from React + Node

Solved
Highlighted
Shopify Partner
20 2 13

Hi all,

 

I've been following the Node and React Shopify app tutorial, and have managed to get basically everything working. I can access the GraphQL API no problem, and have written a few of my own queries and mutations. However, some of the data I need is only available through the Shopify REST API.

 

I've read through the Shopify OAuth guide and I'm able to retrieve a valid access_token. I'm using that to send a GET request to retrieve a list of collections, but I get a 401 Unauthorized response. I've tried using Postman to test the exact request, and it works fine. 

 

Is there anything special I need to do? Is it possible that some of the GraphQL code from the demo is interfering? I've posted my code below, in case it's helpful.

 

 

    fetch("https://my-fake-demo-store.myshopify.com/admin/api/2019-04/custom_collections.json", {
      mode: 'no-cors',
      method: 'GET',
      headers: {
        "X-Shopify-Access-Token": accessToken,
	"Content-type": "application/json",
      },
    }).then(response => {
      console.log(response)
      return response;
    }).then(json => {
      console.log(json)
    });

 

 

0 Likes
Highlighted
Shopify Staff
Shopify Staff
1555 81 282

Would you be able to provide an X-Request-Id response header after replicating? That would give me a look at the logs to see what might be happening.

 

Cheers.

0 Likes
Highlighted
Shopify Partner
20 2 13

@Alex sure thing, I just added the X-Request-Id with a value of "thresher_collections_rest_api_test" to my header. Thanks for your response!

0 Likes
Highlighted
Shopify Staff
Shopify Staff
1555 81 282

Sorry for the confusion! I meant could you capture a response header which we provide called x-request-id. This will be a unique value I can use to track down logs.

 

Cheers!

0 Likes
Highlighted
Shopify Partner
20 2 13

@Alex apologies, wasn't 100% sure what you were asking. I attached an image showing the response I get back from the above fetch request. The response.headers seem to be empty. Does my code above look correct, or am I missing something?

 

Screen Shot 2019-05-01 at 1.16.56 PM.png

 

0 Likes
Highlighted
Shopify Partner
20 2 13

So after doing some more digging, it looks like I can't query the REST API because the requests are coming directly from my app frontend instead of backend. Does that make sense?

 

Are there examples of how to connect to the REST API via Node JS server + React app?

 

Edit: it appears that is the case. I'm able to access the REST API from my server.js file with the following code:

fetch("https://" + shop + "/admin/api/2019-04/custom_collections.json", {
  headers: {
    "X-Shopify-Access-Token": accessToken,
  },
})
.then(response => response.json())
.then(json => console.log(json))

I'm not sure how to set this up so I can call the API from my React front end though.

0 Likes
Highlighted
Shopify Partner
20 2 13

This is an accepted solution.

I managed to figure this out, and wanted to share an update in case anyone runs into the same issue. My problem was that my API calls were coming from the frontend instead of the backend and they were being rejected. My solution was to create my own backend routes and call them from my frontend.

 

1. Add koa-router to server.js

const Router = require('koa-router');
const router = new Router();

2. Add custom backend routes to make API calls to Shopify:

router.get('/api/:object', async (ctx) => {
    try {
      const results = await fetch("https://" + ctx.cookies.get('shopOrigin') + "/admin/api/2019-04/" + ctx.params.object + ".json", {
        headers: {
          "X-Shopify-Access-Token": ctx.cookies.get('accessToken'),
        },
      })
      .then(response => response.json())
      .then(json => {
        return json;
      });
      ctx.body = {
        status: 'success',
        data: results
      };
    } catch (err) {
      console.log(err)
    }
  })

3. Call backend routes from React frontend:

getCollections = () => {
    var fetchUrl = "/api/custom_collections";
    var method = "GET";
    fetch(fetchUrl, { method: method })
    .then(response => response.json())
    .then(json => console.log(json))
  }

I'm not sure if this is the most effective solution, so feel free to chime in if you have suggestions to improve this.

4 Likes
Highlighted
Tourist
9 0 1

Hi Thresher, tried your solution, still getting 401. Where did you add the custom backend route in server.js? I have no backend experience, and I'm really confused...

app.prepare().then(()=>{
   const server = new Koa();
   server.use(session(server));
   server.keys = [SHOPIFY_API_SECRET_KEY];

   server.use(
     createShopifyAuth({
       apiKey: SHOPIFY_API_KEY,
       secret: SHOPIFY_API_SECRET_KEY,
       scopes: ['read_products', 'read_orders', 'write_products'],
       afterAuth(ctx) {
         const { shop, accessToken } = ctx.session;
         
            ctx.cookies.set('shopOrigin', shop, { httpOnly: false });
         ctx.redirect('/');
       },
     }),
   );

   server.use(graphQLProxy({version: ApiVersion.April19}));
   server.use(verifyRequest());
   server.use(async (ctx) => {
       await handle(ctx.req, ctx.res);
       ctx.respond = false;
       ctx.res.statusCode = 200;
       return
   });

   router.get('/api/:object', async (ctx) => {
    try {
      const results = await fetch("https://" + ctx.cookies.get('shopOrigin') + "/admin/api/2019-04/" + ctx.params.object + ".json", {
        headers: {
          "X-Shopify-Access-Token": ctx.cookies.get('accessToken'),
        },
      })
      .then(response => response.json())
      .then(json => {
        return json;
      });
      ctx.body = {
        status: 'success',
        data: results
      };
    } catch (err) {
      console.log(err)
    }
  })

   server.listen(port, () => {
     console.log(`> Ready on http://localhost:${port}`);
   });

 

0 Likes
Highlighted
Shopify Partner
20 2 13

@Ireneludi make sure that you include the code from step 1 at the top of server.js. You're missing a line below where you set the shopOrigin cookie:

ctx.cookies.set('accessToken', accessToken);

Let me know if that works!

1 Like
Highlighted
Tourist
9 0 1

@Thresher got this error  GET https://bd73afd9.ngrok.io/api/orders 404 (Not Found)

and my frontend fetch function is like

const fetchUrl = '/api/orders';
		const method = "GET";
		fetch(fetchUrl, {method: method,})
		.then(response=>response.json()).then(json => console.log(json))

then I tried to change the fetchUrl

const fetchUrl = 'https://getordertest.myshopify.com/api/orders.json';
		const method = "GET";
		fetch(fetchUrl, {method: method,})
		.then(response=>response.json()).then(json => console.log(json))

and I got : Access to fetch at 'https://getordertest.myshopify.com/api/orders.json' from origin 'https://bd73afd9.ngrok.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

 

And I add {mode: 'no-cors'}

and I just got an opaque response...

0 Likes