Fetch request with FormData Object - javascript

I am trying to send html table inside append of FormData object using fetch request.
Code is Correct for these
let formData = new FormData();
formData.append('sponsor', "My sponsor");
formData.append('rider', "xRider");
But When trying to send an html in it Fetch request fails
formData.append('delegation', "<b>Bold Text</b>");
My complete request
fetch(request_url, {
method: 'POST',
processData: false,
contentType: false,
body: formData
})
.then(response => {
if (response.ok) return response.json();
})
.then(response => {
let response_status = response['status'] == 'success' ? 'success' : 'failed';
// In case of OK, this sendResponse will be called
Console.log("Working correctly")
})
.catch(error => {
// In case of error, this sendResponse will be called
call_back_function({
status: "failed",
data: error
});
console.log('%c View Visa Details Catch Error: ', 'background: #000; color: #bada55', error)
});

So this is an example from an actual project I am making. I don't see all of your code, so I can't see you request, or headers. But try something like this! or post all of your code so we can properly see everything.
export const NewPost = async(endpoint, body) =>
{
const headers = new Headers();
headers.append('Content-Type', 'application/json');
const options = {
method:'POST',
body: JSON.stringify(body),
headers:headers,
};
const request = new Request(endpoint, options);
const response = await fetch(request).then((response) =>
{
if(response.ok)
return response.json();
throw new Error(`Response not received. Status: ${response.status}`);
})
.then((json) =>
{
console.log(`POST Request successful.`);
return json;
})
.catch(error => console.log(error));
return response;
};

Related

How to access property of stringified JSON?

I have this code that sends me back an url and an error. I'm trying to access the url so I can navigate to it with router.
With this code:
const redirectToStripe = async () => {
const response = await fetch(
"http://localhost:5000/create-checkout-session",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(cartItems.value),
}
)
.then((response) => response.json())
.then((response) =>
console.log("stringied response", JSON.stringify(response))
);
const { url } = await response.json();
console.log("url=", url); <--------------Doesn't execute, no console.log() readout
// window.location.href = url;
// router.go(url) <------- NEED TO FIX THIS AND UNCOMMENT;
};
I get this error:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'json')
at redirectToStripe
and this console.log() readout:
stringied response {"url":"https://checkout.stripe.com/c/pay/cs_test_a1X3r92YtZfM9H"}
That is the url I'm trying to navigate to, but I don't know how to access it in this stringified form. How do I grab the value of "url" so I can put it in the function:
router.go(url)
The later "url" console.log() never executes because of the json error (pretty sure), but I'm guessing it's the same url as the stringified one above?
I also don't know why I'm getting that error or if it's even consequential and needs to be fixed because I'm already getting the url I need. Does the error have something to do with the "Content-Type" header? Did I pick the right one? Is it something else I'm doing wrong?
Also, this is what the backend endpoint looks like if it adds context or anything.
app.post("/create-checkout-session", async (req, res) => {
// Make an array of just our Stripe Price ID and quantities
const lineItems = req.body.map((item) => {
console.log("lineItems= ", item.item.priceId, item.item.quantity);
return {
price: item.item.priceId,
quantity: item.item.quantity,
};
});
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: lineItems,
success_url: `http://localhost:8080/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `http://localhost:8080/`,
});
return res.send({ url: session.url });
});
EDITS
#pope_maverick
This code:
const redirectToStripe = () => {
const response = fetch("http://localhost:5000/create-checkout-session", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(cartItems.value),
}).then((response) => response.json());
const {url} = response.json();
// const { url } = await response.json();
console.log("url=", url);
gets me the error:
Uncaught TypeError: response.json is not a function
You forgot to return the response in your last .then callback. So your const response is actually void.
const response = await fetch(
"http://localhost:5000/create-checkout-session",
// [...]
)
.then((response) => response.json())
.then((response) => {
console.log("stringied response", JSON.stringify(response))
// ❗️ Return `response` here, or the Promise will return the returned value of `console.log` which is `void`!
return response
});
You face this issue because the API returns a string not an object so you are suppsed to use Response.text() over Response.json(), have a look the MDN Response.text()
Try below:
const redirectToStripe = async () => {
const response = await fetch(
"http://localhost:5000/create-checkout-session",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(cartItems.value),
}
)
.then(response => response.text())
.then((url) => {
const { url } = url;
console.log("url=", url);
router.go(url)
})
.catch(err => console.log(err))
};

try to fetch and read the response body as json or fallback to plain text

I'm trying to fetch data from the server, and I want to try to resolve the response body as json, if failed return it as plain text
fetch(`/devapi/${url}`, {
method: 'GET',
headers: new Headers({
Authorization: `Bearer ${localStorage.getItem("token")}`,
}),
})
.then((res) =>
res
.json()
.then((res) => res?.body?.data || res?.body || res)
.catch((err) => res.text())
)
.then((val) => console.log(val));
when the response is NOT a valid json, ten res.text() is called, but it seems that calling .text() after .json causes an error
Failed to execute 'text' on 'Response': body stream already read
You could clone the response, and then use it in error handler:
Try this:
fetch(`/devapi/${url}`, {
method: 'GET',
headers: new Headers({
Authorization: `Bearer ${localStorage.getItem("token")}`,
}),
})
.then((res) => {
const clone = res.clone();
return res
.json()
.then((res) => res?.body?.data || res?.body || res)
.catch((err) => clone.text())
})
.then((val) => console.log(val));
or use XHR and process response in a try/catch:
const xhr = new XMLHttpRequest();
xhr.open('POST', `/devapi/${url}`, true);
xhr.setRequestHeader('Authorization', `Bearer ${localStorage.getItem("token")}`);
xhr.onload = function() {
let res;
try {
res = JSON.parse(xhr.response);
} catch (err) {
res = xhr.responseText;
}
console.log(res);
};
xhr.send();

axios vs fetch throwing error on file upload

I am using fetch instead of axios in my react project
my this method working fine with the axios to upload an image on the server
Upload image function
<Upload customRequest={dummyRequest} className="upload-btn-container" onChange={onChange}>
<Button className="btn custom-upload-btn">Upload Image</Button>
</Upload>
const uploadPicture = async (data) =>{
const value = await getUploadPicture(data)
if(value.value.data.status){
await addImage(value.value.data.data)
}
}
const onChange = async (info) => {
for (let i = 0; i < info.fileList.length; i++) {
const data = new FormData();
data.append('file', info.fileList[i]);
data.append('filename', info.fileList[i].name);
setImgName(info.fileList[i].name)
let value = await uploadPicture(data);
}
};
return axios({
method: 'post',
url: `${NewHostName}/upload`,
headers: {
'Content-Type': 'application/json',
'Authorization': localStorage.getItem('authToken')
},
data:data
})
.then(response => {
return response
}).catch(err => {
console.log("err", err)
})
whereas when I do same with the fetch it throws me error on the backend "Cannot read property of split of undefined"
return fetch(`${NewHostName}/upload`, {
method: "post",
headers: {
"Content-Type": "application/json",
Authorization: localStorage.getItem('authToken'),
},
body: JSON.stringify(data),
// body :data
})
.then((res) => {
return res.json();
})
.then((payload) => {
return payload;
})
.catch((err) => {
throw err;
})
Not sure what is the reason behind this
this is my backend upload api
const handler = async (request, reply) => {
try {
const filename = request.payload.filename
const fileExtension = filename.split('.').pop()
AWS.config.update({
accessKeyId: Config.get('/aws').accessKeyId,
secretAccessKey: Config.get('/aws').secretAccessKey,
region: Config.get('/aws').region
})
const s3 = new AWS.S3({
params: {
Bucket: Config.get('/aws').bucket
}
})
const Key = `/${shortid.generate()}.${fileExtension}`
const obj = {
Body: request.payload.file,
Key,
ACL: 'public-read'
}
s3.upload(obj, async (err, data) => {
if (err) {
return reply({ status: false, 'message': err.message, data: '' }).code(Constants.HTTP402)
} else if (data) {
return reply({ status: true, 'message': 'ok', data: data.Location }).code(Constants.HTTP200)
}
})
} catch (error) {
return reply({
status: false,
message: error.message,
data: ''
})
}
}
data is a FormData object.
In your original code you are lying when you say 'Content-Type': 'application/json'. Possibly Axios recognises that you've passed it a FormData object and ignores your attempt to override the Content-Type.
Your fetch code, on the other hand, says body: JSON.stringify(data) which tries to stringify the FormData object and ends up with "{}" which has none of your data in it.
Don't claim you are sending JSON
Don't pass your FormData object through JSON.stringify
For image upload you not use JSON.stringify(data).You can try with formData and append an image file with form data.
var formdata = new FormData();
formdata.append("image", data);
Did you check that
const filename = request.payload.filename
exists?
Is the key really payload? The following does not make any changes to your code:
.then((payload) => {
return payload;
})

2 API Calls in One JavaScript

presently I am attempting to make 2 different api calls one after the other within 1 java/nodejs script. It seems after my first function runs successfully, the second one errors with the following:
FetchError: request to failed, reason: socket hang up;
type: 'system',
errno: 'ECONNRESET',
code: 'ECONNRESET'
Below is a code snippet of what I have tried thus far:
const fetch = require("node-fetch");
const formData = require("form-data");
const fs = require("fs");
//const express = require("express");
var apiName = "<LOCAL SYSTEM FILE TO UPLOAD>";
var lookupName = "<LOCAL SYSTEM FILE TO UPLOAD>";
var accessToken = "Bearer <ACCESS TOKEN>";
var url = '<URL API #1>';
var url2 = '<URL API #2>;
var headers = {
'Accept': 'application/json',
'Authorization': accessToken,
};
const form = new formData();
const buffer2 = fs.readFileSync(lookupName);
const buffer = fs.readFileSync(apiName);
const uploadAPI = function uploadAPI() {
form.append("Content-Type", "application/octect-stream");
form.append('file', buffer);
fetch(url, {method: 'POST', headers: headers, body: form})
.then(data => {
console.log(data)
})
.catch(err => {
console.log(err)
});
};
const uploadLookup = function uploadLookup() {
form.append("Content-Type", "application/octect-stream");
form.append('file', buffer2);
fetch(url2, {method: 'PUT', headers: headers, body: form})
.then(data => {
console.log(data)
})
.catch(err => {
console.log(err)
});
};
if (!apiName !== true) {
uploadAPI()
} else {}
if (!lookupName !== true) {
console.log("Uploading Lookup File");
uploadLookup()
} else {}
I tried using a "setTimeout" function which does not seem to work as I would have liked it to. My best guess is each API call would need to be it's own separate socket connection? Any help with getting me in the right direction is appreciated.
Promise.all([
fetch(url),
fetch(url2)
]).then(function (res) {
// Get a JSON object from each of the responses
return res.json();
}).then(function (data) {
// do something with both sets of data here
console.log(data);
}).catch(function (error) {
// if there's an error, log it
});

Capturing Responses other than 200 OK From Fetch

I'm using the native fetch library as specified here. It seems that whenever a response other than a 200 OK is returned it throws an exception with the string response Uncaught (in promise) TypeError: Failed to fetch.
Was there a way to catch and branch on specific HTTP response codes and still view the response data? For example a 401 response?
I have attached my request code I am using as a wrapper for fetch.
static request(url, data) {
let headers = {
"Authorization": window.localStorage.getItem("Authorization"),
"Content-Type": "application/json"
};
let options = {
method: "GET",
headers: headers,
mode: "no-cors",
cache: "no-cache",
};
if (data) {
options = {
method: "POST",
headers: headers,
mode: "no-cors",
cache: "no-cache",
body: JSON.stringify(data)
}
}
return new Promise(async (resolve, reject) => {
try {
let response = await fetch(url, options);
let jsonResponse = await response.json();
return resolve(jsonResponse);
} catch (error) {
// hashHistory.push("/login");
return reject(error);
}
})
}
"An accurate check for a successful fetch() would include checking that the promise resolved, then checking that the Response.ok property has a value of true. The code would look something like this (https://developer.mozilla.org/pt-BR/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful):
fetch('flowers.jpg').then(function(response) {
if(response.ok) {
response.blob().then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
} else {
console.log('Network response was not ok.');
}
})
.catch(function(error) {
console.log('There has been a problem with your fetch operation: ' + error.message);
});
"
You can check Response Headers .status property, .text() to read Response. If Response is expected to be read more than once, you can use .clone()
let request = fetch("/path/to/resource");
request
.then(response => {
const status = response.headers.get("status");
console.log(status);
if (status == 401) {
// read 401 response
response.text().then(res = > console.log(res));
return "404.html"
}
if (status == 200) {
return "200.html"
}
})
.then(result => console.log(result))
.catch(err => // handle error);

Categories