skip to Main Content

I’m trying to post a local zip file to an endpoint using axios to be used in an async code from the main.
This works well with Postman.
The endpoint accept a file and a hash as str.

static async sendConf() {
    const dataFolder =
      process.env.NODE_ENV === 'development'
        ? path.join(__dirname, '../../data')
        : path.join(app.getPath('userData'), '/data');
    await Utilities.zipDirectory(
      dataFolder,
      path.join(dataFolder, 'conf.zip'),
    ).then(async (r) => {
      const fs = require('fs');
      const form_data = new FormData();
      fs.readFile(path.join(dataFolder, 'conf.zip'), async (error, data) => {
        form_data.append('hash', TOKEN);
        const bb = new Blob([data]);
        form_data.append('file', bb, {
          contentType: 'multipart/form-data',
          filename: 'conf.zip',
        });

        const response = await Utilities.postAxios('upload-conf', {
          data: form_data,
        })
          .then((r) => {
            console.log(`done`);
          })
          .catch((e) => {
            console.log(`sendConf err : ${e}`);
          });
        console.log(`sendConf : ${response}`);
      });
    });
  }

And postAxios looks like this :

static async postAxios(url, params) {
    const obj = await Utilities.readConfFile('settings');
    const authAxios = axios.create({
      baseURL: obj.generalSettings.warehouse,
    });
    try {
      const { data } = await authAxios.post(
        url,
        { ...params },
        {
          headers: {
            'Content-Type': 'multipart/form-data',
          },
        },
      );
      return data;
    } catch (error) {
      console.log(error);
    }
  }

It gives the error below, any help ?

TypeError: source.on is not a function
    at Function.DelayedStream.create (/project/node_modules/delayed-stream/lib/delayed_stream.js:33:10)
    at FormData.CombinedStream.append (/project/node_modules/combined-stream/lib/combined_stream.js:45:37)
    at FormData.append (/project/node_modules/form-data/lib/form_data.js:75:3)
    at FormData.defaultVisitor (/project/node_modules/axios/lib/helpers/toFormData.js:175:14)
    at each (/project/node_modules/axios/lib/helpers/toFormData.js:198:73)
    at Object.forEach (/project/node_modules/axios/lib/utils.js:267:10)
    at build (/project/node_modules/axios/lib/helpers/toFormData.js:197:11)
    at toFormData (/project/node_modules/axios/lib/helpers/toFormData.js:214:3)
    at Object.transformRequest (/project/node_modules/axios/lib/defaults/index.js:84:16)
    at transform (/project/node_modules/axios/lib/core/transformData.js:22:15)
    at Axios.request (/project/node_modules/axios/lib/core/Axios.js:45:41)
    at async Function.postAxios (/project/src/main/utilities.ts:114:24)
    at async /project/src/main/utilities.ts:297:26

Post local file to an endpoint API using Electron 26.2.1 and axios 1.7.7

2

Answers


  1. Chosen as BEST ANSWER

    This implementation did the trick, for whom can't change versions :

    static async sendConf() {
        const dataFolder =
          process.env.NODE_ENV === 'development'
            ? path.join(__dirname, '../../data')
            : path.join(app.getPath('userData'), '/data');
        await Utilities.zipDirectory(
          dataFolder,
          path.join(dataFolder, 'conf.zip'),
        ).then(async (r) => {
          const fs = require('fs');
          const form_data = new FormData();
          form_data.append('hash', TOKEN);
          // need to await 
          const file = await blob(
            fs.createReadStream(path.join(dataFolder, 'conf.zip')),
          );
          form_data.append('file', file, 'conf.zip');
          const response = await Utilities.postAxios('upload-conf', form_data)
            .then((r) => {
              console.log(`done`);
            })
            .catch((e) => {
              console.log(`sendConf err : ${e}`);
            });
          console.log(`sendConf : ${response}`);
        });
      }
    

    With : import { blob } from 'node:stream/consumers';


  2. The error you’re seeing (TypeError: source.on is not a function) occurs because Axios expects a Node.js Readable stream when working with file uploads, but a Blob (which is typically used in browser environments) is being provided. Here’s how you can fix the code by using Node.js fs streams instead

    server.js

    const express = require("express");
    const multer = require("multer");
    const path = require("path");
    const app = express();
    
    // Configure multer to save uploaded files in the 'uploads' folder
    const upload = multer({ dest: path.join(__dirname, "uploads/") });
    
    app.post("/upload-conf", upload.single("file"), (req, res) => {
      console.log("File received:", req.file);
      console.log("Hash received:", req.body.hash);
      res.json({ status: "success", message: "File uploaded successfully" });
    });
    
    const PORT = 3000;
    app.listen(PORT, () => {
      console.log(`Test server running on http://localhost:${PORT}`);
    });
    

    client.js

    const axios = require("axios");
    const FormData = require("form-data");
    const fs = require("fs");
    const path = require("path");
    
    const dataFolder = path.join(__dirname, "data"); // Path to the data folder
    const TOKEN = "test-token"; // Replace with a test token value
    const filePath = path.join(dataFolder, "conf.zip");
    
    // Function to post data using Axios
    const Utilities = {
      async postAxios(url, formData) {
        const authAxios = axios.create({
          baseURL: "http://localhost:3000", // Point to the local test server
        });
    
        try {
          const { data } = await authAxios.post(url, formData, {
            headers: {
              ...formData.getHeaders(), // Axios uses these headers for multipart form-data
            },
          });
          return data;
        } catch (error) {
          console.log("Error posting data:", error);
          throw error;
        }
      },
    };
    
    // Test function to send the file
    (async () => {
      const form_data = new FormData();
      form_data.append("hash", TOKEN);
    
      // Create a read stream and append it directly to the form_data
      const fileStream = fs.createReadStream(filePath);
      form_data.append("file", fileStream, "conf.zip");
    
      try {
        const response = await Utilities.postAxios("/upload-conf", form_data);
        console.log(`sendConf : ${JSON.stringify(response)}`);
      } catch (e) {
        console.log(`sendConf err : ${e}`);
      }
    })();
    

    package.json

    {
      "name": "zip-question",
      "version": "1.0.0",
      "main": "index.js",
      "scripts": {
        "start-server": "node server.js",
        "test-client": "node client.js"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "description": "",
      "dependencies": {
        "axios": "^1.7.7",
        "express": "^4.21.1",
        "form-data": "^4.0.1",
        "fs": "^0.0.1-security",
        "multer": "^1.4.5-lts.1",
        "path": "^0.12.7"
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search