I am trying to send text and formData in one fetch call to a Node.js backend using multer.
I can send formData on its own with no issues, but when I try and add text, the api call stays 'pending'.
Here is my fetch call that works just with formData:
const handleImage = async (e) => {
var formData = new FormData();
let file = e.target.files[0];
formData.append("image", file);
try {
const upload = await fetch(
`${process.env.NEXT_PUBLIC_SERVER_API}/uploadImage`,
{
method: "POST",
body: formData,
}
);
} catch (e) {
console.log("Something went wrong!");
}
};
Here is the same fetch call with text added that does not work:
const handleImage = async (e) => {
var formData = new FormData();
let file = e.target.files[0];
formData.append("image", file);
try {
const upload = await fetch(
`${process.env.NEXT_PUBLIC_SERVER_API}/uploadImage`,
{
method: "POST",
body: {formData, userId}
}
);
} catch (e) {
console.log("Something went wrong!");
}
};
It also doesn't work if I try and user JSON.stringify().
I do believe that you can't send a formData and json body at the same time (maybe there is a way somehow i don't know)
because multer will just take the file from formdata and the other property will be set to req.body so if you want to send userId you can try
const handleImage = async (e) => {
var formData = new FormData();
let file = e.target.files[0];
formData.append("image", file);
formData.append("userId", userId);
try {
const upload = await fetch(
`${process.env.NEXT_PUBLIC_SERVER_API}/uploadImage`,
{
method: "POST",
body: formData,
}
);
} catch (e) {
console.log("Something went wrong!");
}
};
Related
This question already has answers here:
try/catch blocks with async/await
(10 answers)
Closed 8 months ago.
In my Next.js app, I'm calling an upload function which contains the then and catch functions.
export const uploadDocument = async (url: UploadURLs, file: File) => {
const formData = new FormData();
formData.append("file", file);
await fetch(`${someEndpoint}`, {
method: "POST",
body: formData,
})
.then(() => notify(`Awesome, it worked.`, "success"))
.catch(() => notify("An error occurred.", "error"));
};
Note: The notify function is a wrapper function firing a toast notification, and isn't really important to my question.
From my component, I'm calling the uploadDocument function. Everything is working, but I can't stop router.push(nextPage) from firing (shown below), regardless of whether the uploadDocument function succeeds or not.
I want to keep the then and catch logic inside the uploadDocument function, but also would like to have the calling component know whether or not the upload succeeded, so I could prevent the page change.
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await uploadDocument(
"certificate",
file
)
router.push(nextPage); // This always fires, but should be conditional
};
I tried to capture the result of the function call, but get undefined regardless of upload success/failure:
const result = await uploadDocument("certificate", file);
if (result.success) router.push(nextPage);
Try this approach:
export const uploadDocument = (url: UploadURLs, file: File) => {
const formData = new FormData();
formData.append("file", file);
return fetch(`${someEndpoint}`, {
method: "POST",
body: formData,
})
};
Then you can catch the error with an try /catch
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
await uploadDocument(
"certificate",
file
)
notify(`Awesome, it worked.`, "success")
router.push(nextPage);
} catch(err) {
notify("An error occurred.", "error")
}
};
I followed the advice of #kemicofa-ghost, as they pointed out in the comments, and arrived at a working solution.
export const uploadDocument = async (url: UploadURLs, file: File) => {
const formData = new FormData();
formData.append("file", file);
try {
await fetch(`${someEndpoint}`, {
method: "POST",
body: formData,
});
notify(`Your file ${file.name} was uploaded successfully`, "success");
return true;
} catch (error) {
notify(
"An error occurred while uploading the file. Please try again.",
"error"
);
return false;
}
};
And then:
const result = await uploadDocument(
"certificate",
companyInfo2.incorporationCertificate
);
if (result) router.push(nextPage);
You can keep your logic in your function:
type UploadResponse = {
error: boolean;
message: string;
}
export const uploadDocument = async (url: UploadURLs, file: File): Promise<UploadResponse> => {
try {
const formData = new FormData();
formData.append("file", file);
await fetch(`${someEndpoint}`, {
method: "POST",
body: formData,
})
return {error: false, message: "Awesome, it worked"}
} catch(e) {
return {error: true, message: "An error occurred"}
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const result = await uploadDocument(
"certificate",
file
)
notify(result.message);
if (!result.error) {
router.push(nextPage);
}
};
I need to include the image as binary data in my uploading request using multipart form data, and it seems not working, any advise will be appreciated.
my code:
const [selectedFile, setSelectedFile] = useState(null);
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('selectedFile', new Blob([selectedFile], { type: 'application/octet-stream' }));
const data = {
uploadLink,
formData,
};
const headers = {
'Content-Type': 'application/octet-stream' ,
Accept: 'application/vnd.vimeo.*+json;version=3.4',
};
try {
await axios
.post(`${backendPostPath}/thumbnail-upload`, data, {
headers,
})
.then((response) => {
applyThumbnial();
console.log(response);
});
} catch (error) {
console.log(error);
}
};
const handleFileSelect = (event) => {
setSelectedFile(event.target.files[0]);
};
include formData as axios data parameter instead of your data object, so you can also include uploadLink in the formData:
const formData = new FormData();
formData.append('selectedFile', new Blob([selectedFile], { type: 'application/octet-stream' }));
formData.append('uploadLink', uploadLink)
//...
await axios
.post(`${backendPostPath}/thumbnail-upload`, formData, {
headers,
})
Hi I have a backend which receive a request with a picture and storage, I try it with postman and with the code below and works perfectly
var axios = require('axios')
var FormData = require('form-data')
var fs = require('fs')
var data = new FormData()
data.append('file', fs.createReadStream('index.png'))
console.log('HEADERS')
console.log(data.getHeaders())
let config = {
method: 'post',
url: 'http://localhost:5013/v1/business/honda/widget/test/',
headers: {
...data.getHeaders(),
},
data: data,
}
The problem is in my vue app I try to do it with the next code, I have 2 buttons with one load the image and the other to send it.
In the back end I have the follow error when try to pick 'file'
http: no such file
let imageData
//send the image to backend
function funtest() {
console.log('image')
const formData = new FormData()
const url = 'http://localhost:5013/v1/business/honda/widget/test/'
formData.append('file', imageData)
let config = {
method: 'post',
url: url,
headers: {
'Content-type': 'multipart/form-data',
},
data: formData,
}
axios(config)
.then((response) => {
console.log('RESPONSE')
console.log(response)
})
.catch((error) => {
console.log('ERROR')
console.log(error)
})
}
//function to read the image
function onImage(data) {
const reader = new FileReader()
reader.onload = (e) => {
imageData = e.target.result
console.log('imagen')
}
reader.readAsDataURL(data.target.files[0])
}
I think it's probably not reading the path to index.png file correctly here, fs.createReadStream('index.png')
Consider using path like this
const path = require('path');
const filePath = path.join(__dirname, 'index.png');
data.append('file', fs.createReadStream(filePath))
NB: This is just a quick and dirty suggestion, and it's not guaranteed to work but it's definitely worth a shot
I am trying to set up "Cloudinary" for image uploads from my React app.
My submit function keeps responding with: "Bad Gateway 502" and "SyntaxError: Unexpected end of input".
I'm assuming something is wrong with my headers, but I can't find the issue...
handleFileSelect = (e) => {
this.formValid()
this.setState({
picture: e.target.files[0] })
}
submit(){
const CLOUDINARY_URL=
"https://api.cloudinary.com/v1_1/dvz27u2gu/image/upload"
const CLOUDINARY_UPLOAD_PRESET= "jshvp3nh"
const obj = Object.assign({}, this.state);
const formData = new FormData();
formData.append("file", obj.picture);
formData.append("upload_preset", CLOUDINARY_UPLOAD_PRESET);
fetch(CLOUDINARY_URL,{
mode: 'no-cors',
method:'post',
headers: { "Content-Type": "application/x-www-form-urlencoded"},
body:formData,
})
.then((res)=>{return res.json()})
.then(data=>console.log(data))
.catch(err=>console.log(err));
}
You can try something like the following:
<div><input type="file" onChange={this.submit}/></div>
submit = (e) => {
var file = e.target.files[0];
var data = new FormData();
data.append('upload_preset', 'jshvp3nh');
data.append('file', file);
data.append('cloud_name', 'dvz27u2gu');
const config = {
method: "POST",
body: data
};
var imgurl = "https://api.cloudinary.com/v1_1/dvz27u2gu/raw/upload";
fetch(imgurl, config)
.then(responseData => {
console.log('here');
console.log(JSON.stringify(responseData, null, 4));
console.log(responseData);
})}
This is how it worked for me.
const CLOUDINARY_URL= "https://api.cloudinary.com/v1_1/dvz27u2gu/image/upload"
const CLOUDINARY_UPLOAD_PRESET= "jshvp3nh"
const obj = Object.assign({}, this.state);
const formData = new FormData();
formData.append("file", obj.picture);
formData.append("api_key", "xx")
formData.append("api_secret", "xx")
formData.append("upload_preset", CLOUDINARY_UPLOAD_PRESET);
formData.append("timestamp", (Date.now() / 1000) | 0);
fetch(CLOUDINARY_URL,{
method:'POST',
body: formData,
})
.then((res)=>{return res.json()})
.then((data)=>{
obj.img_url_cloudinary=data.secure_url;
this.sendForm(obj);
}).catch(err=>console.log(err));;
I have an API that receives uploads of APP files and images
To send from APP to the API I use fetch
const data = new FormData();
let i = 0;
export const dataPush = (fileUri, fileType, fileName) => {
data.append('file'+i, {
uri: fileUri,
type: fileType,
name: fileName
});
i++;
};
export const uploadFiles = () => {
console.log(data);
fetch('http://192.168.0.23/apiapp/public/api/annex', {
method: 'post',
body: data
}).then(res => {
console.log(res)
});
}
But I'd like to send in the same request data obtained from a form
But I did not find a way to do it, always or just send the data, or just send the files
Is it possible to send everything in the same request? And if possible, how?
You just append whatever data that you desire that isn't file data to the FormData object.
data.append("not_a_file", "This is a string");
I did so based on Quentin's response and it worked
const formData = new FormData();
const i = 0;
export const filePush = (fileUri, fileType, fileName) => {
formData.append('file'+i, {
uri: fileUri,
type: fileType,
name: fileName
});
i++;
};
export const dataPush = (name, content) => {
formData.append(name, content);
};
export const uploadFiles = () => {
fetch('http://192.168.0.23/apiapp/public/api/annex', {
method: 'post',
body: formData
}).then(res => {
console.log(res._bodyText)
}).catch(error => {
console.log(error.message)
});
}