Search code examples
node.jsreactjsimageherokufrontend

How to display binary images retrieved from API in React.js?


✨ Hello everyone!✨

General Problem:

I have a web app that has about 50 images that shouldn't be able to be accessed before the user logs into the site. This should be a simple answer I suspect, there are plenty of sites that also require this basic protection. Maybe I do not know the right words to google here, but I am having a bit of trouble. Any help is appreciated.

App details:

My web app is built in typescript react, with a node.js/express/mongoDB backend. Fairly typical stuff.

What I have tried:

My best thought so far was to upload them into the public folder on the backend server hosted on heroku. Then I protected the images with authenication middlewear to any url that had "/images/" as a part of it. This works, partially. I am able to see the images when I call the api from postman with the authenication header. But I cannot figure out a way to display that image in my react web app. Here is the basic call I used.

fetch(url,
        {
            headers: {
                Authorization:token,
            },
        }
    ); 

and then the actual response is just an empty object when I try to copy it {} but I also get this when I console log the pure response, some kind of readable stream:

console reponse to my fetch request

from following related question

I came up with the following: (which is normally wrapped in a asyc function)

const image = await fetch(url,{headers:{ Authorization:token}}); 
const theBlob = await image.blob();
console.log(URL.createObjectURL(theBlob));

which gives me the link: http://localhost:3000/b299feb8-6ee2-433d-bf05-05bce01516b3 which only displays a blank page.

Any help is very much appreciated! Thanks! 😄


Solution

  • After lots of work trying to understand whats going on, here is my own answer:

    const image = await axios(url, { responseType: "blob", headers: {Authorization: token }}); 
    const srcForImage = URL.createObjectURL(image.data)
    

    Why it makes sense now

    So I did not understand the innerworkings of what was going on. Please correct me, but the following is my understanding:

    So the image was being sent in binary. What I had to do to fix that was to set the reponseType in axios as "blob", which then sent a blob, which I believe means its base 64 encoded instead. Then the function URL.createObjectURL does some magic, and must save it to the browser as part of the page. Then we can just use that as the image url. When you visit it yourself, you must type the 'blob:' part of the url it give you too, otherwise its blank, or stick it in <img src={srcForImage}/> and it works great. I bet it would've worked in the original fetch example in the question, I just never put the url in a tag or included 'blob:' as part of the URL.