I'm using node fetch to make API Calls inside a platform.
I need to make an API Call to pass file in form-data.
Below is my stub code:
const fetch = require("node-fetch")
var myHeaders = {"Authorization": "Basic Y2hhdEJvdDpJRkxjYkAxMjM="
,'cache-control': 'no-cache'
,"content-type": "multipart/form-data;"
};
let file_content = "base 64 file content";
let getFormDataForWhatsAppStatement = (data,fileContent,fileExt)=>{
let jsonData = { "data":{ "templateName":"Test_123", "fieldName":"Document_Purpose,Policy_Number,Document_Category", "fieldValue":`AttachDocument, ${data.policyNumber}, Customer_Requirement`, "docList":"Test_Doc" } }
let formDataPairs = [];
let finalFormData = '';
formDataPairs.push(encodeURIComponent("") + '=' + encodeURIComponent(jsonData));
formDataPairs.push(encodeURIComponent("") + '=' + encodeURIComponent(fileContent));
finalFormData = formDataPairs.join('&').replace(/%20/g, '+');
return finalFormData;
}
let formdata = getFormData({"policyNumber":"006558144"},file_content,"png");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata
};
fetch(url, requestOptions)
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.log('error', error));
The error I get here is boundary parameter is not defined.
So I removed the content-type header as stated in the below thread:
Boundary Issue
But then it gives me connection timeout error(since the request format is incorrect).
So is there a way to create formData Similar to the below code without using FormData Object?
const FormData = require('form-data');
const fetch = require("node-fetch")
var formdata = new FormData();
var myHeaders = {"Authorization": "Basic Y2hhdEJvdDpJRkxjYkAxMjM="
//,"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryyEmKNDsBKjB7QEqu"
};
formdata.append("", "{ \n \"data\":{ \n\n \"templateName\":\"Test_123\",\n \"fieldName\":\"Document_Purpose,Policy_Number,Document_Category\",\n \"fieldValue\":\"AttachDocument, G0000784, Customer_Requirement\",\n \"docList\":\"Test_Doc\" \n}\n}\n");
formdata.append("", "base 64 file data", "close.png");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch(API_URL, requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
Instead of literally inputting the boundary have you tried using the form-data function getBoundary() and assigning it to a variable like so:
let boundary = formdata.getBoundary();
var myHeaders = {"Authorization": "Basic Y2hhdEJvdDpJRkxjYkAxMjM="
"Content-Type": `multipart/form-data; boundary=${boundary}`
};
Related
I am trying to upload SVG data using fetch API and multipart/form-data content-type but its throwing 400 error code.
var myHeaders = new Headers();
myHeaders.append("Content-type", "multipart/form-data");
var formData = new FormData();
formData.append("front_svg",stage.canvas.toSVG());
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formData,
redirect: 'follow'
};
fetch("api-url", requestOptions).then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
I'm using an API to make my login page validate the user and password with this code:
function ola() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
//WITH USERNAME AND PASSWORD LIKE THIS VVVVVV
var raw = "{\r\n \"password\": \"Olasou1!\",\r\n \"username\": \"bernardo\"\r\n}\r\n";
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("https://api.secureme.pt/api/v1/auth/login", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
};
I get a success message so I know that it worked
But when I try to use the user inputs on the variable raw like this:
function ola() {
var user = document.getElementById("user").value;
var password = document.getElementById("password").value;
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
var raw = {
password: password,
username: user
};
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("https://api.secureme.pt/api/v1/auth/login", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
};
And when I put the same username and password, I get an error saying that it failed to fetch:
error TypeError: Failed to fetch
at ola (:5500/js/loginRegister.js:36:3)
at HTMLButtonElement.onclick (loginRegister.html:22:74)
I can't figure out why, can someone help me with this?
This is where I call the function on html file:
<button type="submit" class="submit-btn" onclick="ola()">Log In</button>
Try to serialize your raw data:
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(raw),
redirect: 'follow'
}
You can check fetch documents for more details about which data types allowed by request body:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body
https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters
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);
});
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());
});
I have a herokuapp deployed on heroku and it can pass all of my postman test. However, when I try to send a request to the herokuapp link through fetch using another project's button, it always fail and break the herokuapp. I'm trying to use the herokuapp as a server and it is already connected with my mongo database.
I copy pasted the code from var myHeaders straight from postman's code generating function.
Here is the code for my request, I have a username and a password input on the page and this function is designed for the sign in button:
function signin() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("username", "dandan");
urlencoded.append("password", "123");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
***mode: 'no-cors'***// This will make it work, but I don't know why
};
fetch("https://emma-game-server.herokuapp.com/signin", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
[UPDATED] I figured out adding mode:'no-cors' will give me the response, but as a noob I don't totally understand.
[UPDATED AGAIN] I figured out that I don't need 'no-cors' and I need to change the request form, here's the final alteration that worked:
function signin() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({"username":username,"password":password});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("https://emma-game-server.herokuapp.com/signin", requestOptions)
.then(response => response.json())
.then(result => {
console.log(result);
if (result.success){
alert("Signed in as " + result.username);
document.getElementById("user").innerHTML=username;
}
else{
alert(result.message);
}
})
.catch(error => console.log('error', error));
}