Search code examples
javascriptnode.jsfile-uploadmultipart

how can I send an image binary via post to an API? nodejs


I am getting the image binary like this:

axios.get("image-url.jpg")

I need to use the response for making a new POST request to another server

  const form = new FormData();
  const url = "post-url-here.com";
  form.append(
    "file",
    new ReadableStream(Buffer.from(file)),
    "image-test.jpg"
  );
  const config = {
    headers: {
      ...form.getHeaders(),
      Authorization:
        "Bearer token-here",
    },
  };
  axios.post(url, form, config);

Unfortunately that isn't working. The response I am getting is:

data: {
  message: 'This file is not compatible with the picture engine, please try another one',
  error: 'bad_request',
  status: 400,
  cause: []
}

How can I properly do that ?

edit: form.getheaders is adding this headeer to the request:

'content-type': 'multipart/form-data; boundary=--------------------------783115116498484087556627'

all request headers:

headers: {
  Accept: 'application/json, text/plain, */*',
  'Content-Type': 'multipart/form-data; boundary=--------------------------918731250556909112992344',
  Authorization: 'Bearer token-here',
  'User-Agent': 'axios/0.21.1'
},

all request information:

_header: 'POST /pictures/items/upload HTTP/1.1\r\n' +
  'Accept: application/json, text/plain, */*\r\n' +
  'Content-Type: multipart/form-data; boundary=--------------------------116660171215340291632150\r\n' +
  'Authorization: Bearer token-here\r\n' +
  'User-Agent: axios/0.21.1\r\n' +
  'Host: api.mercadolibre.com\r\n' +
  'Connection: close\r\n' +
  'Transfer-Encoding: chunked\r\n' +
  '\r\n',

Solution

  • An example of POST Header:

    POST /video-upload/ HTTP/1.1
    Host: your host 
    User-Agent: axios/0.21.1
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Language: it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Content-Type: multipart/form-data; boundary=---------------------------219493771727403213993181042749
    Content-Length: 99211703
    Connection: keep-alive
    

    as you can see there are important parts like:

    POST /the-url/ HTTP/1.1
    Host: your host 
    Content-Length: the length in bytes of your image 
    Content-Type: multipart/form-data; boundary=---------------------------219493771727403213993181042749
    Connection: keep-alive
    

    So your script do not read the images , your header is broken as status:400 response from Server says.

    Try this (pseudo code) :

    const axios = require('axios');
    const fs = require('fs');
    
    var im_config = {
        responseType: 'stream'
    };
    
    let im_url =  'image-url' ;
    
    async function getImage() {
        let resp = await axios.get(im_url, im_config);
        //save the image
        resp.data.pipe(fs.createWriteStream('test-image.jpg'));
    }
    
    getImage().then(function(result){
    
      console.log(result); 
    
      const form = new FormData();
      const url = "server url where send the form ";
    
      // interesting part 
      form.append('image', 'test-image.jpg');   
      axios.post(url, form, your-config);
    
    });
    
    

    It worked! Ok.

    To do it on the fly , try to abtain a refer to the downloaded image from 'result' or 'resp' without saving the image.

    Otherwise unlink downloaded image after POST is done.

    fs.unlink('test-image.jpg', (err) => {
      if (err) {
        console.error(err)
        return
      }
    }