Display image from server

Hi, I am trying to display an image from my backend to my ionic 5 app.
The request works in postman, my server returns a readablestream (using mongodb) with image/jpeg as header. But for my ionic app I am able to display it in ionic serve but when I try on real device its not displayed (it display the default icon’ broken image’ + image name). Here is the code I use in my dashboard.ts

getUserAvatar(){
  this.userService.getUserAvatar().subscribe(
    (res: any) => {
      if (res.error ) {

      }
      else {
        console.log(res)
        this.createImageFromBlob(res);

      }
    })
}


createImageFromBlob(image: Blob) {
   let reader = new FileReader();
   reader.addEventListener("load", () => {
      this.userAvatar = reader.result;
      console.log(this.userAvatar)
   }, false);

   if (image) {
      reader.readAsDataURL(image);
   }
}

my html : <div (click)="chooseAvatar()" class="bmjContainer inlineBlock"><a><ion-img [src]="userAvatar" alt="bitmojiLink" class="bmjLogo"></ion-img></a></div>

and my userService.ts :

  getUserAvatar() : Observable<Blob>{
    return this.http.get(`${baseUrl}/chatApp/getUserAvatar`,{responseType: "blob"});
  }

any idea why its not correctly displayed only on real android device ? :confused:

To store files / pictures / etc. is not the best practice in NoSQL.
I would suggest to use some external service as a storage.
Try to use FirebaseStorage it is quite easy to implelment into Ionic env.

Hi, could you precise what’s not the best practice ? and my whole backend is built in mongodb, I already use this bucket system to store musics and its working very fine, however for images I get this weird bug

It seems to me like you’re mysteriously reimplementing part of HTTP. What I would do instead of any of the blobbing or dataurling would be to have getUserAvatar return a URL - an actual https://my-backend-server/avatars/foobar0123.png sort of URL (or simply include this avatar URL as part of your User business interface). Then it can be passed directly through a bound parameter in an <img [src]="user.avatar">, and you let the browser do all the junk you’re trying to do manually - it’s better at it.

Now we’ve moved the problem to the backend, where your middleware server accepts requests to /avatars/:userid and sends back the same JPEG stream you’re sending now.

1 Like

Hi, thanks for your answer, no mistery here I first searched throught stackoverflow and found this “old” post https://stackoverflow.com/questions/45530752/getting-image-from-api-in-angular-4-5
so I followed it :confused:

May I post the backend code here then ?

EDIT : here is my backend code (performing a get request through postman or my browser works but as I said above I dont know how to handle it in ionic)

 async getUserAvatar(req, res) {
        await user.findOne({ _id: req.decoded.id })

            .then(result => {

                let length = 0
                try {
        
                    var avatarId =  new ObjectID(result.avatarId)
        
                } catch (err) {
                    return res.status(400).json({ message: "Invalid avatarID" });
                }
                db.collection('images.files').findOne({ _id: avatarId }, function (err, item) {
                    if (item) {
                        length = item.length;
        
                    }
        
                    if (err) {
                        return res.status(400).json({ message: "Invalid trackID in URL parameter. Must be a single String of 12 bytes or a string of 24 hex characters" });
                    }
        
                    res.set('content-type', 'image/jpeg');
                    res.set('accept-ranges', 'bytes');
                    res.set('content-length', JSON.stringify(length));
        
                    let bucket = new mongodb.GridFSBucket(db, {
                        bucketName: 'images'
                    });
        
    
                    let downloadStream = bucket.openDownloadStream(avatarId);
        
                    downloadStream.on('data', (chunk) => {
                        res.write(chunk);
        
                    });
        
        
                    downloadStream.on('error', () => {
                        res.sendStatus(404);
                    });
        
                    downloadStream.on('end', () => {
                        res.end();
                    });
                });

            })
            .catch(err => {
                res.status(500).json({ message: 'Error Occured finding user by id' });
            });
       
    }

Edit 2 : please dont mind the error message I return, I’m learning by myself and my code is not “clear” yet :slight_smile:

you can finde here some detailied explanation:

almost every service provider (amazon, google, etc) created different cloud service for file storage.

1 Like

Thank you guys for your answers, I understood my mistakes, I will first implement correctly my avatar request putting the http://…/myavatar.png in a variable, then put this variable as my source for my image tag. Then I will look for firebase cloud service or something to prepare when my app willl need to scale (hopefully :slight_smile: )