I'm trying to post multipart/form-data using axios. I can send the post request using Postman/Insomnia successfully but it is not working from frontend.
It gives an error in my backend:
node:events:505
throw er; // Unhandled 'error' event
^
TypeError: Cannot read properties of undefined (reading '0')
Also in browser console it shows:
Error: Network Error
at createError (createError.js:16:1)
at XMLHttpRequest.handleError (xhr.js:117:1)
POST http://localhost:8080/audio?= net::ERR_CONNECTION_REFUSED
Here is my frontend code in reactjs. Can anyone help me please?
import { React, useState, useEffect } from 'react';
import AppBar from '@mui/material/AppBar';
import axios from 'axios';
import { useNavigate,useLocation} from "react-router-dom";
import { toast } from 'react-toastify';
import Toolbar from '@mui/material/Toolbar';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import ArrowBack from '@mui/icons-material/ArrowBack';
import { Box, Button, Container, Link, Grid, TextField, Typography } from '@mui/material';
const theme = createTheme();
export default function AddNewAudio() {
let navigate = useNavigate();
let location = useLocation();
const [title, setTitle] = useState("");
const [artistName, setartistName] = useState("");
const [owner, setOwner] = useState("");
const [thumbnail, setThumbnail] = useState("");
const [audioFile, setAudioFile] = useState("");
const [isLoading, setIsLoading] = useState(false);
const HandleChange = (event) => {
event.preventDefault();
setTitle(document.getElementById('title').value)
setartistName(document.getElementById('artistName').value)
setOwner(document.getElementById('owner').value)
}
const HandleThumbnail = (event) => {
setThumbnail([event.target.files[0]]);
setIsLoading(true);
}
const HandleAudioFile = (event) => {
setAudioFile([event.target.files[0]]);
setIsLoading(true);
}
const FileUploadHandler = (event) => {
event.preventDefault();
let form = new FormData();
form.append('title', {title});
form.append('artistName', {artistName});
form.append('owner', {owner});
form.append('thumbnail', {thumbnail});
form.append('audioFile', {audioFile});
const config = {
method: 'post',
url: 'http://localhost:8080/audio',
params: {'': ''},
data: '[form]'
}
const promise = axios(config)
.then((response) => {
if(response.status == 200){
navigate('/audiolisting',{state:{token:"Token"} });
setIsLoading(false);
}
})
.catch(function (error) {
console.log(error);
setIsLoading(false);
if(error.status == 413){
toast.error("Your File greater than maximum Uploading Limit");
}
else{
toast.error("Error");
}
});
toast.promise(
promise,
{
pending: {
render(){
return "Loading..."
},
icon: false,
},
success: {
render(){
return `Added successfully!`
},
icon: "",
}
}
);
console.log("title", {title});
console.log("artistName", {artistName});
console.log("owner", {owner});
console.log("thumbnail", {thumbnail});
console.log("audioFile", {audioFile});
}
return (
<ThemeProvider theme={theme}>
<AppBar position="relative">
<Toolbar>
{/* <CameraIcon sx={{ mr: 2 }} /> */}
<Typography variant="h6" color="inherit" noWrap>
Planet Q Production
</Typography>
</Toolbar>
</AppBar>
<main>
<Box
style={{background:"white", margin:"2%"}}
sx={{
bgcolor: 'background.paper',
pt: 8,
pb: 6,
}}
>
<Container >
<Grid container spacing={2}>
<Grid item xs={8}>
</Grid>
<Grid item xs={4}>
<Button variant="outlined" startIcon={<ArrowBack />} style={{float:"right", marginBottom:"-65px"}} onClick={backToListing}>
Back to listing
</Button>
</Grid>
</Grid>
<div>
<form encType="multipart/form">
<input
type="text"
name="title"
id="title"
placeholder="Song title"
onChange={HandleChange}
/>
<br/>
<input
type="text"
name="artistName"
id="artistName"
placeholder="Artist Name"
onChange={HandleChange}
/>
<br/>
<input
type="text"
name="owner"
id="owner"
placeholder="Owner"
onChange={HandleChange}
/>
<br/>
<input
type="file"
name="thumbnail"
id="thumbnail"
placeholder="Upload your file"
onChange={HandleThumbnail}
/>
<br/>
<input
type="file"
name="audioFile"
id="audioFile"
placeholder="Upload your file"
onChange={HandleAudioFile}
/>
<br/>
<button
type="submit"
onClick={FileUploadHandler}
>Submit</button>
</form>
</div>
</Container>
</Box>
</main>
</ThemeProvider>
);
}
const express = require("express");
const router = express.Router();
const Audio = require('../models/Audio')
const multer = require('multer')
const baseUrl = "http://localhost:8080/audio/";
const mongoose = require('mongoose');
const storage = multer.diskStorage({
filename: function (req, file, cb) {
console.log('filename')
cb(null, file.originalname)
},
destination: function (req, file, cb) {
console.log('storage')
cb(null, __basedir + "/uploads/audio/");
},
})
const upload = multer({ storage })
router.get('/', async (req, res) => {
const audios = await Audio.find();
res.status(200).send({
success: true,
data: audios,
message: 'Audio retrived successfully'
})
});
const CounterSchema={
id: { type: String }, seq: {type: Number}
}
const countermodel = module.exports = mongoose.model('counter', CounterSchema);
router.post('/', upload.fields([{ name: 'thumbnail' }, { name: 'audioFile' },]), async (req, res) => {
countermodel.findOneAndUpdate(
{ id: "autoval" },
{ "$inc": { "seq": 1 } },
{ new: true }, (err, cd) => {
if (cd == null) {
const newval = new countermodel({ id: "autoval", seq: 1 })
newval.save()
seqId = 1
} else {
seqId = cd.seq
}
const audio = new Audio({
id: seqId,
title: req.body.title,
artistName: req.body.artistName,
owner: req.body.owner,
thumbnail: baseUrl + req.files['thumbnail'][0].filename,
audioFile: baseUrl + req.files['audioFile'][0].filename
});
try {
const savedAudio = audio.save();
res.json(audio);
} catch (err) {
res.json({ message: err });
}
})
});
module.exports = router;
The client code generated by Insomnia shows that it needs to be the full path of the file. But after some research I found out it is not possible to get full path of the selected files. (How to get absolute path of image in react `<input ="file" />` and store it in local state?)
import axios from "axios";
const form = new FormData();
form.append("title", "Test Song");
form.append("artistName", "Test Artist");
form.append("owner", "Test Owner");
form.append("thumbnail", "/home/rafin/Desktop/test.jpg");
form.append("audioFile", "/home/rafin/Downloads/audio/new.mp3");
const options = {
method: 'POST',
url: 'http://localhost:8080/audio',
params: {'': ''},
headers: {'Content-Type': 'multipart/form-data; boundary=---011000010111000001101001'},
data: '[form]'
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});