-2

I am new to node js and i am developing the server-side of my nuxt project. actually i want to send a file to an external api but i get error Callback must be a function

in my server.js

let formidable = require('formidable');
const bodyParser = require('body-parser')
const app = require('express')()
const cookieParser = require('cookie-parser')
var fs = require('fs');
const cors = require('cors');

const fileUploadController = require("./controllers/fileUploadController");
app.use('/uploads', fileUploadController.uploadFile)

in my fileUploadController.js

function uploadFile(req, res, next) {
   const axios = require('axios');
   const FormData = require('form-data');
   const fs = require('fs');

   const image =  fs.readFile('./down.png');

   const form = new FormData();
   form.append('productName', 'Node.js Stickers');
   form.append('productDescription', 'Cool collection of Node.js stickers for your laptop.');
    form.append('productImage', image, 'down.png');

   const response =  axios.post('http://api.com/api/nuxt', form, {
    headers: 
    {
     'Content-Type': 'multipart/form-data',
     }  
   });
 }

 module.exports = {uploadFile} 
marjan
  • 97
  • 7
  • Please specify what errors you encounter and the API specifics. Did you write the API yourself or are you using an external service? – code Aug 21 '22 at 04:31
  • does your `server.js` handle `multipart/form-data` body? – Jaromanda X Aug 21 '22 at 04:32
  • @code Actually it is written in the question title that i am new to node js and using an external api – marjan Aug 21 '22 at 04:38
  • @Jaromanda X I am not sure honestly i should npm install fordata and import FormData, { diskStorage, memoryStorage, FormDataError, } from '@multipart/form-data' ? – marjan Aug 21 '22 at 04:40
  • 2
    It does not matter whether you're new or not: by reading [ask] you should know to provide all helpful information, especially errors; we have no idea how the API wishes to receive data so it's impossible with your information to help you in any way. Besides that, external API _does not necessarily_ denote an API you didn't write; it's just not on the same server. Please edit your question accordingly. – code Aug 21 '22 at 04:42
  • @marjan - I don't know - I'd be looking at nodejs libraries that handle incoming multipart requests, rather than what you suggest, which is a library for creating multipart requests – Jaromanda X Aug 21 '22 at 04:47
  • @code thanks for mentioning that i will edit my question and for more information here i get this error `Callback must be a function` – marjan Aug 21 '22 at 05:09
  • For the error, which file did it say it was on, and what was the line number? – code Aug 21 '22 at 05:26
  • @code it is response in network tab error Object { message: "Callback must be a function", name: "TypeError [ERR_INVALID_CALLBACK]", frames: […] } message "Callback must be a function" – marjan Aug 21 '22 at 05:43
  • All JavaScript errors tell you the file and line number from which it originated. Please post that. – code Aug 21 '22 at 05:49
  • The file you require in your main code isn't `uploadFile.js`. Are you are aware of that? – code Aug 21 '22 at 05:50
  • @code it is getting error from this line const image = fs.readFile('./down.png'); – marjan Aug 21 '22 at 05:59
  • @code actually it is fileUploadController.js i will edit my q – marjan Aug 21 '22 at 06:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/247421/discussion-between-marjan-and-code). – marjan Aug 21 '22 at 06:06
  • Ohhhh, when you read a file like that you must pass it a function to get the data, see https://nodejs.org/en/knowledge/file-system/how-to-read-files-in-nodejs/, or off you can't figure it out you could use [`fs.readFileSync`](https://sebhastian.com/fs-readfilesync/). Honestly I feel kind of stupid for not seeing that. – code Aug 21 '22 at 15:19

1 Answers1

1

In fileUploadController.js you're using fs's APIs incorrectly. fs.readFile takes a callback; it does not return your file. Your code should look somewhat like this:

// fileUploadController.js
function uploadFile(req, res, next) {
  const axios = require('axios');
  const FormData = require('form-data');
  const fs = require('fs');

  fs.readFile('./down.png', async function(err, image) => {

    const form = new FormData();
    form.append('productName', 'Node.js Stickers');
    form.append('productDescription', 'Cool collection of Node.js stickers for your laptop.');
    form.append('productImage', image, 'down.png');

    const response = await axios.post('http://api.com/api/nuxt', form, {
      headers: {
        'Content-Type': 'multipart/form-data',
      }
    });
  });
}

module.exports = {
  uploadFile
};

The reason this takes a callback is because JavaScript is asynchronous and doesn't wait for fs to finish reading the file before moving on, so you have to give the function something to execute once it's finished.

I wouldn't personally use callbacks though; you could use fs.readFileSync or the promise version.

Besides that, as pointed out in the comments, axios returns a promise, so you should be awaiting it (also notice the async preceding the current function declaration).

code
  • 5,690
  • 4
  • 17
  • 39
  • This is indeed correct, however the `axios.post` function call is also asynchronous and should be awaited. – emeraldsanto Aug 22 '22 at 00:05
  • @emeraldsanto yes, I technically answered his question by fixing the error he mentioned, but I've adjusted my answer anyway, thanks. – code Aug 22 '22 at 00:08