I’m currently working on building a React book finder app that talks with Goodreads’ API. My backend skills are lacking so I wanted to undergo this project to improve on that. But I’m having trouble talking to Goodreads’ API; whenever I try to fetch a response and console.log(...) it, I get a 401 (Unauthorized) Error:
In case its too hard to read, I seem to be getting the error because:
Access to fetch at ‘this URL’ from origin ‘my computer’ 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.
My first question is: How do I set the request’s mode to be ‘no-cors’?
My second question is: Is this recommended? Or is there a better, more sound way of getting past the 401 error?
At the end of the day, I just want to be able to display search results but I need to be able to draw from Goodreads’ API in order to display the data.
Look at the API key being passed in the url params in the network tab. It says your API key is api_key, which would suggest you haven’t passed that variable in properly.
It’s hard to say without seeing your code, but if a variable is undefined it could just be that it’s out of scope - i.e. the part of the code that calls the variable can’t see it because it is defined in a block it doesn’t have access to.
I see. I did store the key in a separate .env file because I read that it was a secure way of hiding API keys but still being able to use them? Therefore, it would be out of scope.
If you have a backend api that can do the fetch for you and then feed the data you need to your frontend app, then you’re all set. But any call to the API from your frontend directly will expose your API key.
One solution I use (which sucks, but works) is to create an input field for users to paste their own api key in, and then I read that from local storage.
I don’t know what your familiarity is with React - but the principle is the same in normal javascript, too. Get the key from the user, save it to storage, then load the key from storage.
In my example it basically works like a password field.
Option 1 is like my example above. Ask your user for their api key and then save that to local storage. Read the key value from local storage when you need it. Because it’s saved to local storage they only need to do this once (unless their clear their cache).
Option 2 is to make a backend api of your own that communicates with GoodReads directly on your behalf. The journey to get the data would look something like this:
Your front end asks your backend for data.
Your backend asks the GoodReads api for that data.
Your backend sends it to your frontend.
I’ve actually wanted to figure out option 2 properly for ages, so I had a go at implementing a simple backend to act as a request relay.
You can take a look at this to see how I did it.
I used the GoodReads API so it’s more useful to you. The bad thing about GR is that they only serve XML for the search queries, so there’s a little more messing around turning it into JSON for easy use in your front end!
So I think I found out why I was getting that TypeError: fetchGoodReads is an immediately-invoked function expression (IIFE). I’m guessing that means it can’t be imported in app.js?