Generate body for multipart file upload using fetch in Javascript - javascript

I am trying to upload a file(uploadType=multipart) to Drive API V3 using fetch but the body is wrong as it is creating a file with the title unnamed.
var tmpFile=document.getElementById('inputFile').files;
tmpFile=tmpFile[0];
await fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', {
method: 'POST', // or 'PUT'
headers: {
'Authorization': 'Bearer '+accessToken,
},
body: {
metadata:{
'name':tmpFile.name,
'Content-Type':'application/json; charset=UTF-8'
},
media:{
'Content-Type': '*/*',
'name':tmpFile
}
}
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});

Your metadata is not being properly uploaded if its uploading with a name of unnamed
const fs = require("fs");
const FormData = require("form-data");
const fetch = require("node-fetch");
const filePath = "./sample.txt";
const accessToken = "###";
token = req.body.token;
var formData = new FormData();
var fileMetadata = {
name: "sample.txt",
};
formData.append("metadata", JSON.stringify(fileMetadata), {
contentType: "application/json",
});
formData.append("data", fs.createReadStream(filePath), {
filename: "sample.txt",
contentType: "text/plain",
});
fetch("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart", {
method: "POST",
body: formData,
headers: { Authorization: "Bearer " + accessToken },
})
.then((res) => res.json())
.then(console.log);
Uploading Files of multipart/form-data to Google Drive using Drive API with Node.js

Related

React native image upload getting network error

'react-native-image-picker' for uploading image in my application, Sometimes it is uploading and sometimes i am getting [TypeError: Network request failed] below is the code:
FormData in my component:
//image is :file:///data/user/0/com.testApp/cache/rn_image_picker_lib_temp_0d38d959-6ece-4750-a215-4b3f68002f4e.jpg
let formData = new FormData();
formData.append('images', { uri:image, name: imageSelected?.fileName, type: 'image/png' });
const response = await updateUserProfile(userDetails,formData)
Service call:
export const updateUserProfile = async (userDetails,data) => {
const response = await fetch(`${baseUrl}/updateusersprofile/${userDetails._id}`, {
method: "PATCH",
headers: {
//"Content-Type": "application/json",
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${userDetails.token}`,
},
body: data,
});
return await response;
};
In Postman i have checked the api is working fine, What would be the problem in my code.
export const updateUserProfile = async (userDetails,data) => {
const response = await fetch(`${baseUrl}/updateusersprofile/${userDetails._id}`, {
method: "PATCH",
headers: {
//"Content-Type": "application/json",
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${userDetails.token}`,
},
body: JSON.stringify(data),
});
return await response;
};

Can't save state in React while POST API request

I have handleSubmit function that send two POST request, one for img upload and one for other information. I want to take the response from the img upload request and take the 'filename' and then store it in state so I can sent it with the other POST request.
Here is my Request Options
const postOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.serviceToken}`
},
body: JSON.stringify({
p_emp_id: empId,
p_pr_doc_type: docType,
p_from_date: fromDate,
p_to_date: toDate,
p_doc_number: docNumber,
p_addres: address,
p_addres_en: addressEN,
p_doc_store: docPath,
p_creator_id: creator,
p_org_id: org
})
};
Then here is my Handle Submit function
const handleSubmit = async (e) => {
e.preventDefault();
const data = new FormData();
data.append('file', selectedFiles);
await fetch(`${config.apiHost}single/`, {
method: 'POST',
body: data
})
.then((res) => res.json())
.then((img) => setDocPath(img.filename))
.catch((err) => {
console.log(err.message);
});
setEditOpen(false);
fetch(`${config.apiHost}api/employees/info/pr_docs/new/`, postOptions);
console.log(postOptions.body);
};
My state docPath stays empty while I'm trying to submit so after that I can't see it in my request.
you can refactor your code to this and lets see if it works;
let postOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.serviceToken}`
},
body: {
p_emp_id: empId,
p_pr_doc_type: docType,
p_from_date: fromDate,
p_to_date: toDate,
p_doc_number: docNumber,
p_addres: address,
p_addres_en: addressEN,
p_creator_id: creator,
p_org_id: org
}
};
for the handle submit it can be
const handleSubmit = async (e) => {
e.preventDefault();
const data = new FormData();
data.append('file', selectedFiles);
await fetch(`${config.apiHost}single/`, {
method: 'POST',
body: data
})
.then((res) => res.json())
.then((img) => {
const postOptionsBody = {...postOptions.body, p_doc_store : img.filename }
postOptions = {...postOptions, body : JSON.stringify(postOptionsBody) }
setDocPath(img.filename)
})
.catch((err) => {
console.log(err.message);
});
setEditOpen(false);
fetch(`${config.apiHost}api/employees/info/pr_docs/new/`, postOptions);
console.log(postOptions.body);
};

react js fetch api using file upload not being sent to body

Here is my code
let formData = new FormData();
// Update the formData object
formData.append(
"myFile",
this.state.product_picture,
this.state.product_picture.name
);
var options = { content: formData };
const token = JSON.parse(localStorage.getItem('token'));
const requestOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
product_name:this.state.product_name,
product_description:this.state.product_description,
product_picture:formData,
category_name:this.state.category_choosen,
})
};
fetch('http://cms.test/api/products/insert_supplier_product?token='+token, requestOptions)
.then(response => response.json())
.then(data => {
this.setState({ product: data.product})
})
.catch(error =>{
console.log("Product creation error", error);
});
I have this fetch api its always giving a 422 response I think what is happening is that its not reading a file as I want to upload a file it all works in postman but when using react it crashes
The body here is the problem
inside the state there are some strings but inside the this.state.product_picture there is a file
Hope someone can help! Thank you!
SOLUTION: Using axios to call the api solved my problem
You cannot send a file in a JSON object in a request( atleast not without Base64 encoding it). Change your code in the following way to send a file with your form.
let formData = new FormData();
// Update the formData object
formData.append(
"myFile",
this.state.product_picture,
this.state.product_picture.name
);
formData.append("product_name",this.state.product_name);
formData.append("product_description",this.state.product_description);
formData.append("category_name",this.state.category_choosen);
var options = { content: formData };
const token = JSON.parse(localStorage.getItem('token'));
const requestOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
body: formData
};
fetch('http://cms.test/api/products/insert_supplier_product?token='+token, requestOptions)
.then(response => response.json())
.then(data => {
this.setState({ product: data.product})
})
.catch(error =>{
console.log("Product creation error", error);
});

Getting pdf file from api response

I am calling an api and getting pdf in return.
fetch(`api` + guid, {
method: "GET",
headers: {
"Accept": "application/octet-stream",
"Authorization": "Bearer " + token,
},
responseType: 'arraybuffer',
})
.then((res) => res.text())
.then((data) => {
fs.writeFileSync('file.pdf', data);
});
I get the pdf file but the issue is the pdf file is always empty. But when I accept response as json, it works fine.
I found similar problems like this but none of the solution worked for me yet.
It would be great if someone can point out the issue.
I found the issue.
As I am using fetch not Axios.
We cannot pass responseType as Fetch's option.
fetch(`api` + guid, {
method: "GET",
headers: {
"Accept": "application/octet-stream",
"Authorization": "Bearer " + token,
},
// responseType: 'arraybuffer' //#1 remove this,
})
Instead the response in itself can be passed as arraybuffer as below.
.then((res) => res.arraybuffer())
instead of
.then((res) => res.text())
Now instead of directly using the response to write our pdf file. We can change the data to base64 string and decode it back again to create our pdf file. I used base64ToPdf npm package to handle that.
.then(data => {
var base64Str = Buffer.from(data).toString('base64');
base64.base64Decode(base64Str, "file.pdf");
})
I hope this help others. :)
Change res.arraybuffer() to res.arrayBuffer()
Below is the working code with webdriverio-
var headers = {
Authorization: "Bearer " + accessToken,
Accept: 'application/pdf'
}
fetch(
apiurl,
{
headers: {
Accept: "application/octet-stream",
Authorization: "Bearer " + accessToken
},
},
)
.then((res) => {
if (!res.ok) {
return res.status.toString()
}
return res.arrayBuffer()
})
.then((data) => {
var base64Str = Buffer.from(data).toString('base64');
base64.base64Decode(base64Str, filename);
})
.catch(
(err) => {
return err.Message;
})
Here's example which works for me:
async createPdf(context, data) {
let url = new URL(baseURL + '/invoice/createPdf');
url.search = new URLSearchParams({
id: data
})
await fetch(url, {
method: 'GET',
headers: {
'Authorization': "Bearer " + localStorage.getItem("jwt"),
'Accept': 'application/octet-stream'
},
}).then((res) => res.arrayBuffer())
.then(data => {
var base64Str = Buffer.from(data).toString('base64');
var binaryString = window.atob(base64Str);
var binaryLen = binaryString.length;
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
var arrBuffer = bytes;
var newBlob = new Blob([arrBuffer], { type: "application/pdf" });
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob);
return;
}
data = window.URL.createObjectURL(newBlob);
var link = document.createElement('a');
document.body.appendChild(link);
link.href = data;
link.download = "Faktura.pdf";
link.click();
window.URL.revokeObjectURL(data);
link.remove();
})
}
In my case, the response is same as yours and I'm trying to convert it to a pdf file so that I can preview it on the UI.
For this, I need to fetch the URL already present in the response which is of type blob... to fetch the URL I did URL.createObjectURL(myblob)
const [url,seturl] = useState('');
response
.then((resp) => resp.blob())
.then((myBlob) => {
seturl(URL.createObjectURL(myBlob)); //<-- use this for fetching url from your response
console.log(myBlob);
})
.catch((err) => {
console.log(err.message());
});

Javascript node-fetch usage

I can get the data by request from this code.
let request = require('request');
let options = {
'method': 'POST',
'url': 'https://example.com/api',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
'client_id': '12345678',
'client_secret': 'abcdefg'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
However, I got '404.00.001' when I use "fetch" to access the same API. Is there any thing wrong in this code?
const fetch = require("node-fetch");
const url = "https://example.com/api";
var headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
var data = JSON.stringify( {
'client_id': '12345678',
'client_secret': 'abcdefg'
});
fetch(url, {method: 'POST', headers: headers, body: data})
.then(response => response.json())
.then((resp) => {
console.log(resp);
})
.catch(error => console.error('Unable to fetch token.', error));
'Content-Type': 'application/x-www-form-urlencoded' does not say JSON so why do you have var data = JSON.stringify?
The documentation tells you how to encode data as form parameters.
const { URLSearchParams } = require('url');
const params = new URLSearchParams();
params.append('a', 1);

Categories