node.jsfile-uploadaxiosserver-sideimage-upload

NodeJS server side - file Expected UploadFile, received: <class 'str'>


having issues uploading file from NodeJs server side, found 100 posts and reasearches but nothing works, would appreciate any help.

Structure of the App

  1. Front App - React Admin framework receving file and i encode in base64 the content of the image to send to API

  2. Backend - NestJS App - receving base64 image in API

  3. From my backend API need to send file to an external backend (Python API) to upload - here is the problem

Please see below my code, something wrong with the file from JS

i have tried several methods and all of them ends in same error

1 solution

import axios from 'axios';
import FormData from 'form-data';

export async function upload(
  fileBase64: string,
  filename: string
): Promise<any> {

  const buffer = Buffer.from(fileBase64, 'base64')
  const extension = fileBase64.substring(fileBase64.indexOf('/') + 1, fileBase64.indexOf(";base64"))
  const cleanBase64 = fileBase64.replace(/^data:image\/png;base64,/, '')
  const cleanImageBuffer = Buffer.from(cleanBase64, 'base64')

  const formData = new FormData();
  // have tried to pass as well cleanImageBuffer but no changes
  formData.append('file', buffer);
  formData.append('fileName', filename + '.' + extension);
  formData.append('namespace', 'test');
  
  return await axios
    .post('external_api_url', JSON.stringify(formData), {
      headers: {
        Authorization: `Bearer token`,
        ContentType: 'multipart/form-data'
      }
    })
    .then((response) => {
      console.log('response = ' + JSON.stringify(response))
    })

result 1 solution

{
    "status": "error",
    "error": {
        "code": "bad_request",
        "message": "file Expected UploadFile, received: <class 'str'>"
    }
}

2 solution

export async function upload (
  fileBase64: string,
  filename: string
): Promise<any> {

  const extension = fileBase64.substring(fileBase64.indexOf('/') + 1, fileBase64.indexOf(";base64"))
  const cleanBase64 = fileBase64.replace(/^data:image\/png;base64,/, '')

  const TMP_UPLOAD_PATH = '/tmp'

  if (!fs.existsSync(TMP_UPLOAD_PATH)) {
    fs.mkdirSync(TMP_UPLOAD_PATH);
  }

  fs.writeFile(TMP_UPLOAD_PATH + '/' + filename + '.' + extension, cleanBase64, 'base64', function(err) {
    console.log(err);
  })

  const fileStream = fs.createReadStream(TMP_UPLOAD_PATH + '/' + filename + '.' + extension)

  const formData = new FormData();
  formData.append('file', fileStream, filename + '.' + extension);
  formData.append('fileName', filename + '.' + extension);
  formData.append('namespace', 'test');

  return await axios
    .post('external_api_url', formData, {
      headers: {
        Authorization: `Bearer token`,
        ContentType: 'multipart/form-data'
      }
    })
    .then((response) => {
      console.log('response = ' + JSON.stringify(response))
    })
}

result 2 solution

{
    "status": "error",
    "error": {
        "code": "bad_request",
        "message": "file Expected UploadFile, received: <class 'str'>"
    }
}

other solution that ended in same result

best scenario that i need

would appreciate any help

below is a python example that works but not JS (JS nothing works)

import requests

url = "http://127.0.0.1:8000/external_api"

payload={'namespace': 'test'}
files=[
  ('file',('lbl-pic.png',open('/local/path/lbl-pic.png','rb'),'image/png'))
]
headers = {
  'Authorization': 'Bearer token'
}

response = requests.request("POST", url, headers=headers, data=payload, files=files)

print(response.text)

Solution

  • I want to post my solution that worked, because as I can see on the internet everybody have issues with FormData on nodejs

    1. I was using axios to send the buffer for uploading file
    2. issue is with axios and specially with FormData, it does not add Content-Length in headers, any version of axios does not do this
    3. python API had required Content-Length

    If this header becomes optional in python API, the code started to work

    The solution is if anybody have similar issues

    on axios GitHub issue is saying that this bug is fixed in latest axios, but it was still not working in my case

    below is a code by using buffer and Content-Length is not required in 3rd API

        function upload (image: {imageBase64: string, fileName: string}) {
          const { imageBase64, fileName } = image;
          const cleanBase64 = imageBase64.substr(imageBase64.indexOf(',') + 1);
          // buffer should be clean base64
          const buffer = Buffer.from(cleanBase64, 'base64');
        
          const formData = new FormData();
          // filename as option is required, otherwise will not work, will say that received file is string and UploadFile
          formData.append('file', buffer, { filename: fileName });
        
          return client
            .post('url', formData, {
              headers: {
                ...formData.getHeaders(),
              },
            })
            .then((response) => response.data)
            .catch((error) => {
              return {
                status: 'error',
                error,
              };
            });
        }