Node fetch JSON data is not iterable [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I am getting an error of TypeError: data.events is not iterable when using fetch to retrieve JSON data from an API.
I am pretty sure it is in my handling of the JSON in for (const event of data.events) from the below code but I am pulling short on finding a fix.
const data = fetch(url, {
method: 'post',
headers: new Headers({
Authorization: 'Bearer ' + bearerToken,
'Content-Type': 'application/json'
})
});
for (const event of data.events) {
let fileNode;
try {
fileNode = await createRemoteFileNode({
url: logo.original.url,
cache,
store,
createNode,
createNodeId
});
} catch (error) {
console.warn('error creating node', error);
}
}
The JSON when requested in Postman is returned as
{
"pagination": {
...
},
"events": [
{
"name": "Example One",
"logo": {
"original": {
"url": "exampleURL"
}
}
},
{
"name": "Example Two",
"logo": {
"original": {
"url": "exampleURL"
}
}
}
],
"location": {
...
}
}
The goal is to createRemoteFileNode for each event from logo.original.url

fetch() returns a promise so data.events does not exist until the fetch promised is resolved. Edit your code this way:
fetch(url, {
method: 'post',
headers: new Headers({
Authorization: 'Bearer ' + bearerToken,
'Content-Type': 'application/json'
})
}).then(function(data){
for (const event of data.events) {
let fileNode;
try {
fileNode = await createRemoteFileNode({
url: logo.original.url,
cache,
store,
createNode,
createNodeId
});
} catch (error) {
console.warn('error creating node', error);
}
}
});

Related

Cannot upload file with FormData on React Native

I can't upload file with FormData to React Native. I am using react-native-document-picker and here is my code:
try {
const pickerResult = await DocumentPicker.pickSingle({
presentationStyle: 'fullScreen',
copyTo: 'documentDirectory',
type: [DocumentPicker.types.pdf],
mode: 'import',
});
setAccountStatement(pickerResult);
let data = new FormData();
data.append('file', {
uri: pickerResult.fileCopyUri,
type: pickerResult.type,
name: pickerResult.name,
fileName: pickerResult.name,
size: pickerResult.size,
});
console.log(data);
http
.post('url', data, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
}
};
Here's the example response I get from react-native-document-picker
{
"fileCopyUri": "file:///data/user/0/com.crust/files/497ed9ec-79fb-4bfb-81d1-74907f851c08/receipt_20220929065209.pdf",
"name": "receipt_20220929065209.pdf",
"size": 36036,
"type": "application/pdf",
"uri": "content://com.android.providers.media.documents/document/document%3A223934"
}
Please how do I go about this? I get
Error: Request failed with status code 415
from the server and I do not know what I am doing wrong.
So i managed to solve the issue after 2 days of tirelessly trying to figure it out , i managed to have two different solutions to the problem
1. Using Fetch API
const fd = new FormData();
fd.append('file', {
uri: pickerResult.fileCopyUri,
type: pickerResult.type,
name: pickerResult.name,
fileName: pickerResult.name,
size: pickerResult.size,
});
try {
const res = await fetch(
'url',
{
method: 'POST',
mode: 'no-cors',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'multipart/form-data',
},
body: fd,
},
);
console.log(res.status, res.statusText);
if (res.ok) {
console.log('Success');
} else {
console.log(await res.json());
}
} catch (error) {
console.error(error);
}
2. Downgrading Axios to "^0.24.0"
after i figured it out using the fetch api ,i was able to do a deeper research and found out that,
axios has a problem with the FormData() object, from version "^0.25.0"
, so i
downgraded my axios version to "^0.24.0"
and it worked like a charm including image upload using "FormData()"

JavaScript skip await on pending fetch [duplicate]

This question already has answers here:
Fetch API request timeout?
(14 answers)
Closed 8 months ago.
I have an API fetch await code that fetches list of nodes in an array. The problem is, some of the nodes don't respond for whatever reason (being offline, wrong port, being programmed NOT to respond, ... ) and my code is stuck awaiting a reply from that node.
Is there any way to stop awaiting a fetch for example after 3 seconds if no response comes?
I tried using try and catch, but the nodes that don't respond don't return anything, the code is simply sitting there with no error or response.
Thank you!!
// list of nodes
let nodes = [{
"address": {
"hostname": "192.168.1.1",
"port": 31350
}
}, {
"address": {
"hostname": "192.168.1.2",
"port": 31350
}
}
]
// api fetch function
async function fetchNodes(hostname, port) {
const response = await fetch(`https://${hostname}:${port}/getstatus`, {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
});
const data = response.json();
console.log(data);
}
// loop to call api fetch function with all array entries
nodes.forEach(function(entry) {
fetchNodes(entry.address.hostname, entry.address.port);
}
)
try this
async function fetchWithTimeout(resource, options = {}) {
const { timeout = 8000 } = options;
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
const response = await fetch(resource, {
...options,
signal: controller.signal
});
clearTimeout(id);
return response;
}
and use this function in you fetchNodes function
async function fetchNodes() {
try {
const response = await fetchWithTimeout(
`https://${hostname}:${port}/getstatus`,
{
timeout: 6000,
method: "post",
body: JSON.stringify(body),
headers: { "Content-Type": "application/json" },
}
);
const data = await response.json();
return data;
} catch (error) {
// Timeouts if the request takes
// longer than 6 seconds
console.log(error.name === "AbortError");
}
}

Delete user with redux-thunk in firebase

I want to delete a user from firebase. And my action is called from a button.
`
export const deleteAccount = () =>{
return async (dispatch, getState) =>{
const token =getState().auth.token;
let response;
try{
response = await fetch('https://identitytoolkit.googleapis.com/v1/accounts:delete?
key=[My_API_key]',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
token:token
})
});
} catch(err){
throw new Error(err.message);
}
if(!response.ok){
const errorResData = await response.json();
console.log(errorResData);
const errorId = errorResData.error.message;
let message = 'Something went Wrong!';
if(errorId === 'INVALID_ID_TOKEN'){
message = 'Please Login Again!!'
} else if(errorId === "USER_NOT_FOUND"){
message = 'User Not Found';
}
throw new Error(message);
}
// dispatch(authentication(resData.localId, resData.idToken, parseInt(resData.expiresIn)*1000 ));
dispatch({type: DELETE});
}
};
`
on consoling my errorResData I am getting response
Object { "error": Object { "code": 400, "errors": Array [ Object { "domain": "global", "message": "MISSING_ID_TOKEN", "reason": "invalid", }, ], "message": "MISSING_ID_TOKEN", }, }
if I console my token I am getting that token.
Thanks in advance!!
I'm not entirely sure why you aren't using the Firebase SDK to do this, but you should be using v3 of the Identity Toolkit API.
await fetch(
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/deleteAccount",
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
idToken: FRESH_USER_ID_TOKEN
})
}
);

How to put a buffer in an HTTP request?

I’m trying to put a buffer in a request because I have a list of data to import. I want to have success request after one another. The problem I’m encountering is that it waits to upload all data of the request.
Here is the sample data:
[
{
"contacts": "dsds#dsd.com",
"recipient": "dsd#dsd.com",
"date_sent": "07/08/2020 17:05:04",
"subject": "repurchase"
},
{
"contacts": "asd#ret.com",
"recipient": "test#yahoo.com",
"date_sent": "07/10/2020 17:31:51",
"subject": "biz"
},
{
"contacts": "we#sdf.com",
"recipient": "abc#yahoo.com",
"date_sent": "07/09/2020 13:02:54",
"subject": "rock"
}
];
const createEngage = async(body) => {
const BASE_URL = '/api/import'
var requestOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
"Content-Type": "application/json"
},
body: body
};
fetch(BASE_URL, requestOptions)
.then(response => response.text())
.then(async result => {
console.log(result);
})
.catch(error => console.log('error', error));
}
What you probably want to do is to loop over your data and use async / await to wait at each iteration. Your implementation of your asynchronous function currently does not await anything. Instead it should await the fetch request and the decoding of the body with response.text().
Check the response for errors and wrap the fetch request in a try...catch block. If an error occurs then the catch block will be executed. Otherwise check the response object for any states or errors you want to include.
const data = [
{
"contacts": "dsds#dsd.com",
"recipient": "dsd#dsd.com",
"date_sent": "07/08/2020 17:05:04",
"subject": "repurchase"
},
{
"contacts": "asd#ret.com",
"recipient": "test#yahoo.com",
"date_sent": "07/10/2020 17:31:51",
"subject": "biz"
},
{
"contacts": "we#sdf.com",
"recipient": "abc#yahoo.com",
"date_sent": "07/09/2020 13:02:54",
"subject": "rock"
}
];
const BASE_URL = '/api/import'
/**
* Sends a request for each individual item.
*/
const createEngage = async body => {
const requestOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body
};
try {
const response = await fetch(BASE_URL, requestOptions);
if (!response.ok) {
alert('Your request has failed');
return null;
}
const text = await response.text();
return text;
} catch(error) {
alert('Your request caused an error');
}
};
/**
* Loop over each item and call createEngage.
* Wait for the request to finish and continue.
*/
const createMultipleEngages = async data => {
for (const item of data) {
const result = await createEngage(item); // This will make the loop wait every time.
console.log(result);
}
};
// Call the function and start looping.
createMultipleEngages(data);

Axios async problems [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have this axios call with a nested axios call that causes async problems. Here's a simplifyed snippet of my code:
axios.all([
axios.get('https://foo..', {
headers: { 'Content-Type': 'application/json' },
data: { 'endpoint': 'v2/bar..' },
}),
]).then(axios.spread((resp) => {
var resp = resp.data.content;
var items = resp.items.slice(0, 1);
items.forEach(item => {
var dataUrl = item.url.split('/v2/').slice(1).join('');
axios.get('https://foo..', {
headers: { 'Content-Type': 'application/json' },
data: { 'endpoint': 'v2/' + dataUrl + 'bar..' }
}).then(resp => {
const data = resp.data.content;
// alot of code goes here
}
)
}),
axios.get('https://foo..' + pageNum.toString(), {
headers: { 'Content-Type': 'application/json' },
data: {}
}
).then(resp => {
fillTemplate(resp.data.content[0].xml);
}
).catch(function (error) { console.log("DB-GET-Error:\n" + error) });
})
).catch(function (error) { console.log("error " + error) });
The problem is that 'fillTemplate()' executes before 'items.forEach(...)' is done and can populate 'fillTemplate()' with data, how can I solve this?
Problem
Both requests are send async and second won't wait for first one. Solution is to use async/await or Promise.all().
Escaping the callback hell
You are still having the problem of deeply nested code, which becomes unreadable. Below are two examples, first just fixing the issue and second with better readability.
Sample Code
axios.all([
axios.get('https://foo..', {
headers: { 'Content-Type': 'application/json' },
data: { 'endpoint': 'v2/bar..' },
}),
]).then(axios.spread((resp) => {
// cache axios promises here
var promises = []
var resp = resp.data.content;
var items = resp.items.slice(0, 1);
items.forEach(item => {
var dataUrl = item.url.split('/v2/').slice(1).join('');
var promise = axios.get('https://foo..', {
headers: { 'Content-Type': 'application/json' },
data: { 'endpoint': 'v2/' + dataUrl + 'bar..' }
}).then(resp => {
const data = resp.data.content;
// alot of code goes here
});
// add promises to array
promises.push(promise);
});
// wait for all promises to execute next request
Promise.all(promises).then((results) => {
axios.get('https://foo..' + pageNum.toString(), {
headers: { 'Content-Type': 'application/json' },
data: {}
}).then(resp => {
fillTemplate(resp.data.content[0].xml);
}).catch(function (error) { console.log("DB-GET-Error:\n" + error) });
});
})).catch(function (error) { console.log("error " + error) });
Refactored version
axios.all([doStuff()]).then(axios.spread((resp) => {
var promises = []
var resp = resp.data.content;
var items = resp.items.slice(0, 1);
items.forEach(item => {
var dataUrl = item.url.split('/v2/').slice(1).join('');
var promise = doOtherStuff();
promises.push(promise);
});
Promise.all(promises).then(finalCallback).then(resp => {
fillTemplate(resp.data.content[0].xml);
});
}));
function doStuff() {
return axios.get('https://foo..', {
headers: { 'Content-Type': 'application/json' },
data: { 'endpoint': 'v2/bar..' },
});
}
function doOtherStuff() {
return axios.get('https://foo..', {
headers: { 'Content-Type': 'application/json' },
data: { 'endpoint': 'v2/' + dataUrl + 'bar..' }
}
}
function finalCallback(results) {
return axios.get('https://foo..' + pageNum.toString(), {
headers: { 'Content-Type': 'application/json' },
data: {}
});
}

Categories

Resources