5

I am retrieving an image from a REST API via an HTTP GET with a request body.

I've managed to check the returned content via this test using node.js and chai.js:

      expect(res).to.have.header('Content-Type', 'image/jpeg');
      expect(res).to.have.header('Access-Control-Allow-Origin', '*');
      expect(res).to.have.header('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin, X-Requested-With, Content-Type, Accept, Authorization');
      expect(res).to.have.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
      expect(res).to.have.status(200);
      expect(res.body).to.be.instanceof(Buffer); // the image content

In the vue.js file I was used to attach an image to an <img ...> HTML tag like this:

<img v-bind:src="urlImg">

Then specifying in the javascript part the URL like this:

# this string representing the URL is returned by a function
this.urlImg = 'http://example.com/my_img.jpeg' 

but in this case I am not able to provide the URL because the HTTP GET is expecting a body to return the image with content type image/jpeg.

I am not even sure this is possible and I may be misunderstanding how the content type image/jpeg is supposed to work. How do I do this in vue.js? Is it possible at all? Is there a way to check the image content of this HTTP response as with stuff like Postman (Chrome app) I can not inspect the response pretending to treat it as text/Json.

EDIT

Regarding the accepted answer: the last proposed solution (UPDATE 2) worked for me (using HTTP POST providing a JSON body for the request). Make sure you use axios (https://github.com/axios/axios) to perform the HTTP requests (you can import it in the <script> part of the Vue file like this: import axios from "axios";).

I was using vue-resource (https://github.com/pagekit/vue-resource) pretending it was the same as axios, but it is not and it took me a while to realize it.

TPPZ
  • 4,447
  • 10
  • 61
  • 106
  • I dont see any correct question, your url can return something except image or you download image as buffer and you want to show it or what? – Max Sinev Jul 19 '18 at 07:31
  • I am trying to show the image downloaded as buffer from the backend which is returning it as `content-type=image/jpeg`, thanks – TPPZ Jul 19 '18 at 08:01

1 Answers1

10

If you already have Buffer of your image you can specify pre-defined link in your client app:

this.urlImg = '/my/url/to/get/dynamic/image';

And define route to send image from server to client (for Express):

server.get("my/url/to/get/dynamic/image", function(req, res) {
   var myBuffer = yourFunctionReturnsBuffer();
   res.writeHead(200, {
    'Content-Type': 'image/jpeg',
    'Content-Length': myBuffer.length
   });
   res.end(myBuffer); 
 });

Working example for Express+request: My Gist

UPDATE

Load image in browser via ajax (example below). But it is not possible to send request body for GET method with native browser XMLHttpRequest object (this is base for all ajax libraries). From MDN:

send() accepts an optional parameter which lets you specify the request's body; this is primarily used for request such as PUT. If the request method is GET or HEAD, the body parameter is ignored and request body is set to null.

var app = new Vue({
    el: "#app",
    data: {
        // empty image
        src: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
    },
    created() {
        let config = {
            // example url
            url: 'https://www.gravatar.com/avatar/7ad5ab35f81ff2a439baf00829ee6a23',
            method: 'GET',
            responseType: 'blob'
        }
        axios(config)
          .then((response) => {
              let reader = new FileReader();
              reader.readAsDataURL(response.data); 
              reader.onload = () => {
                  this.src = reader.result;
              }
          });
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<div id="app">
  <img :src="src" alt="">
</div>

UPDATE 2

Decode image as array buffer

var app = new Vue({
    el: "#app",
    data: {
        // empty image
        src: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
    },
    created() {
        let config = {
            // example url
            url: 'https://www.gravatar.com/avatar/7ad5ab35f81ff2a439baf00829ee6a23',
            method: 'GET',
            responseType: 'arraybuffer'
        }
        axios(config)
          .then((response) => {
              var bytes = new Uint8Array(response.data);
              var binary = bytes.reduce((data, b) => data += String.fromCharCode(b), '');
              this.src = "data:image/jpeg;base64," + btoa(binary);
          });
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<div id="app">
  <img :src="src" alt="">
</div>
Max Sinev
  • 5,884
  • 2
  • 25
  • 35
  • Is there a way to avoid the backend/Express part? Like running that javascript somehow inside the browser? My current setup is a very thin Vue.js app packaged with webpack and no such node.js backend. I am trying to let the browser part contain just the HTML templates, CSSs and a minimum of javascript code following the "3 blocks HTML/CSS/Js pattern" for files ending in ".vue" Thanks! – TPPZ Jul 19 '18 at 14:02
  • @TPPZ but if you dont have backend how you download file? Why you cant specify image url directly in your Vue app (explain this part better)? – Max Sinev Jul 19 '18 at 14:07
  • To fetch that image I am performing an HTTP GET request providing a request body (similar to HTTP POST), however I can not find a way to specify a body for the HTTP GET of the URL in the `src` attribute of the `` HTML tag. – TPPZ Jul 19 '18 at 14:40
  • @TPPZ oh, I understand. Do you really need to specify **body** for HTTP GET? Maybe it will work with GET parameters? – Max Sinev Jul 19 '18 at 14:52
  • I wished somehow that piece of javascript could have been moved from a backend node.js to somewhere in the browser javascript part? But I am not very familiar with the browser side of things, maybe that buffer thing can not be processed by the browser. At the moment I need the body of the GET request because of a series choices in the past that would require a lot of work if changed so to avoid issues with URL encoding of HTTP query parameters I went with an HTTP request body when performing an HTTP GET request. – TPPZ Jul 19 '18 at 15:30
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/176353/discussion-between-tppz-and-max-sinev). – TPPZ Jul 19 '18 at 18:00