Trying multiple fetch Promises to the same URL, but with a different body to each call. Currently I'm writing them all out. How would I go about writing this in a less verbose fashion?
Promise.all([
fetch("https://cors-anywhere.herokuapp.com/https://api.myurl.com/verify", {
body: `link=${productVariant1}&license_key=${licenseKey}`,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
}).then(do something),
fetch("https://cors-anywhere.herokuapp.com/https://api.myurl.com/verify", {
body: `link=${productVariant2}&license_key=${licenseKey}`,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
}).then(do something),
]).then(data => {
/* process response */
}
There's 5 Promises in total, with only the productVariant part of the call being different.
Sure you can do it with map:
Promise.all([productVariant1, productVariant2].map((productVariant, i) => {
return fetch("https://cors-anywhere.herokuapp.com/https://api.myurl.com/verify", {
body: `link=${productVariant}&license_key=${licenseKey}`,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
}).then(data => console.log(`Promise ${i} done`))
})
).then(data => {
console.log("all promises done")
})
You could create a function:
function Fetch(body) {
return fetch("https://cors-anywhere.herokuapp.com/https://api.myurl.com/verify", {
body,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
}).then(doSomething)
}
// And then
Promise.all([
Fetch(`link=${productVariant2}&license_key=${licenseKey}`),
Fetch(`link=${productVariant2}&license_key=${licenseKey}`)
]).then(responses => {
// do something with responses
})
Or if the only thing you're changing
Related
I need help because I couldn't use a separate function to generate the token - it gives out a promise, not a value. I was told that a value can only be used inside a function.
For each request, I generate a new token in the first request and then pass that token into the second request.
I tried making a separate function to generate the token, but fetch returns a promise.
As a result, I made such a big function and it works.
Is there a way to make a separate function for the first request and pass the result to the second request?
The first token generation function is required frequently, while the second request is always different.
fetch('/api/token', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'id': '5' }),
})
.then(response => response.json())
.then(result => {
fetch('/api/reviews', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + result.token,
},
body: JSON.stringify({ 'limit': 10 }),
})
.then(response => response.json())
.then(result => {
this.setState({ data: result.data });
})
})
create a function that return promise
async function getToken() {
return await fetch('/api/token', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'id': '5' }),
})
.then(response => response.json())
.then(result => {
return Promise.resolve(result.token);
}).catch(error => {
return Promise.reject(error);
})
}
async function getReview() {
const token = await getToken().then(token => {
return token
}).catch(error => {
//handle error
});
fetch('/api/reviews', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token,
},
body: JSON.stringify({ 'limit': 10 }),
})
.then(response => response.json())
.then(result => {
this.setState({ data: result.data });
})
}
i did not test this code but you get the idea
i will test and update my answer asap
Yes you can with async / await. It will allow you to lift the lexical scope of the API response from inside the .then "callback hell" and into the parent function scope.
Your separate function which fetches the token will return a promise, but then the requesting function will wait for the promise to execute and resolve before continuing.
async function fetchToken() {
const response = await fetch('/api/token', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'id': '5' }),
})
return await response.json();
}
async function getReviews() {
const response = await fetch('/api/reviews', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + result.token,
},
body: JSON.stringify({ 'limit': 10 }),
})
const result = await response.json();
this.setState({ data: result.data });
}
Additionally, if the token call does not need to be made every time the reviews call is made, then you can memoize the value, and use that memoized value.
const tokenMemo = useMemo(async () => await getToken(), []);
async function getReviews() {
const response = await fetch('/api/reviews', {
// ...
'Authorization': 'Bearer ' + tokenMemo,
// ...
}
So I am trying to send data from canvas's api using a GET and use that information and send a POST from the same endpoint to discord using node fetch. I can receive data from canvas without issue and I console log to make sure I have to right data, but I can't seem to get any information to discord. I am using discords webhooks and I can't figure out where I am going wrong.
fetch(url + `courses/${course}/discussion_topics` , {
method: "GET",
headers : {
'Authorization' : 'Bearer <auth token>',
'Content-Type' : 'application/json'
}
})
.then(res => res.json())
.then(data => {
console.log(data[0].id);
console.log(data[0].title);
console.log(data[0].message);
}
)
.then(fetch("https://discord.com/api/webhooks/893327519103746149/<webhooktoken>", {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: {content: 'hello world'}
}))
.catch(err => console.log(err))
});```
As mentioned in the comment, just in case you have some typo or misunderstanding.
Also, you need to JSON.stringyify your body.
Please try the example below:
fetch(url + `courses/${course}/discussion_topics`, {
method: "GET",
headers: {
Authorization: "Bearer <auth token>",
"Content-Type": "application/json",
},
})
.then(res => res.json())
.then(data => {
console.log(data[0].id);
console.log(data[0].title);
console.log(data[0].message);
})
.then(() =>
fetch(
"https://discord.com/api/webhooks/893327519103746149/<webhooktoken>",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
username: "Canvas-Bot",
content: "hello world",
}),
}
)
.then(res => res.json())
.then(data => {
console.log({ data });
})
)
.catch(err => console.log(err));
Another approach would be in async/await. I think it is cleaner.
(async function main() {
try {
const res1 = await fetch(url + `courses/${course}/discussion_topics`, {
method: "GET",
headers: {
Authorization: "Bearer <auth token>",
"Content-Type": "application/json",
},
});
const data1 = await res1.json();
console.log(data1);
const res2 = await fetch(
"https://discord.com/api/webhooks/893327519103746149/<webhooktoken>",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
username: "Canvas-Bot",
content: "hello world",
}),
}
);
const data2 = await res2.json();
console.log(data2);
} catch (err) {
console.log(err);
}
})();
I cannot resolve this promise using fetch I want 2 values to go the .then(data)
I want to use the status as wall as the JSON that I got form the back-end,
then inherit the incoming status but the resp.json is always showing a and I cannot access its value any idea ?
fetch('/signup', {
credentials: "same-origin",
mode: "same-origin",
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(inputJSON)
})
.then(resp => {
return [resp.json(), resp.status]
})
.then(function (data) {
console.log(data);
let Status = data[1]
let jsonData = data[0]
let p = jsonData.then(e => { return e })
console.log(p);
})
}
})
fetch('/signup', {
credentials: 'same-origin',
mode: 'same-origin',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(inputJSON),
})
.then((resp) => {
return Promise.all([resp.json(), Promise.resolve(resp.status)]);
})
.then(function (data) {
const [json, status] = data;
console.log(json);
console.log(status);
});
resp.json() returns a Promise, resp.status returns a Number and .then if returns a Promise will resolve it for you but if any other datatype is returned it will not do anything.
So, resp.status is converted to Promise.resolve(resp.status) to turn it into a Promise and returns Promise.all([resp.json(), Promise.resolve(resp.status)]) from .then.
Promise.all will turn multiple Promises into one.
Return a Promise.all to pass both values down the chain:
fetch('/signup', {
credentials: "same-origin",
mode: "same-origin",
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(inputJSON)
})
.then(resp => {
return Promise.all([resp.json(), resp.status]);
})
Or, even better, use async/await, the control flow will be clearer:
const resp = await fetch('/signup', {
credentials: "same-origin",
mode: "same-origin",
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(inputJSON)
});
const result = await resp.json();
// do stuff with result and with resp.status
Make sure to catch possible errors in both cases.
I'm trying to consolidate some code in one of my react components because my componentDidMount method is getting a bit verbose. This gave me the idea to create an api that does all of my data fetching for the entire app.
I'm having an asynchronous issue I'm not sure how to resolve.
I created the separate api file (blurt.js):
exports.getBlurts = function() {
var blurtData = null;
fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then((data) => {
blurtData = data;
});
return blurtData;
}
and imported it to my (.jsx) component via
import blurtapi from '../api/blurt.js';
The problem is that when I call blurtapi.getBlurts() within componentDidMount(), the value comes back as null. However, if I write the data to the console like so:
.then((data) => {
console.log(data);
});
all is as it should be. So, the function is returning before the db operation completes, hence the null value. How would I reign in the asynchronous aspect in this case? I tried an async.series([]) and didn't get anywhere.
Thanks
So fetch returns a promise, which it is async , so any async code will run after sync code. so this is the reason you get null at first.
However by returning the async function , you are returning a promise.
Hence this code:
exports.getBlurts = async () => {
const data = await fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
const jsonData = await data.json();
return jsonData;
}
To retrieve any promise data, you need the then function,
so in your componentDidMount, you will do:
componentDidMoint() {
blurtapi.getBlurts()
.then(data => console.log(data)) // data from promise
}
Promises:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
async/await:
https://javascript.info/async-await
I hope this makes sense.
fetch call returns a promise. therefore in your function u do something like this
exports.getBlurts = function() {
var blurtData = null;
return fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
}
And do this in your componentDidMount
componentDidMount(){
blurtapi.getBlurts().then((data)=>{
this.setState({data})
}
}
In your example return blurtData; line will run synchronously, before the promise is resolved.
Modify getBlurts as:
exports.getBlurts = function() {
return fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then((data) => {
return data;
});
}
And in componentDidMount:
componentDidMount() {
getBlurts.then((data) => {
// data should have value here
});
}
exports.getBlurts = function() {
return fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(res => return res)
async componentDidMount() {
const response = await blurtapi.getBlurts();
}
or
exports.getBlurts = function() {
return fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
componentDidMount() {
const data = blurtapi.getBlurts()
.then(data => {
// Do something or return it
return data;
});
}
so I have 2 endpoints, I'm making a "post" request to the first one and in the response I should get some kind of id that I use in the second request endpoint url. so I want to make a delay or something till I get the response from the first request.
req = () => {
fetch('url', {
method: 'POST',
headers: {
'Authorization': bearer,
'Content-Type': 'application/json',
},
body:
})
.then(response => response.json())
.then(json => {
})
fetch(`url with the id I get from the first request`, {
method: 'GET',
headers: {
'Authorization': bearer,
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(json => {
})
}
There is no need for a delay per se. You can place your second request in the .then of the first request. This will ensure that your second request will run only once the first one has resolved. Another important note here, is that if you need a value of the first response in order to make the second request, you can only do that in the .then of the first request because otherwise the value you need to make the second request will be out of scope. Here is your code with the required modification.
req = () => {
fetch('url', {
method: 'POST',
headers: {
'Authorization': bearer,
'Content-Type': 'application/json',
},
body:
})
.then(response => response.json())
.then(json => {
fetch(`url with json.id or whatever`, {
method: 'GET',
headers: {
'Authorization': bearer,
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(json => {
})
})
}
You can chain your second fetch request in your first request as:
req = () => {
fetch("url", {
method: "POST",
headers: {
Authorization: bearer,
"Content-Type": "application/json"
}
body:
})
.then(response => response.json())
.then(json => {
fetch("url with the id I get from the first request", {
method: "GET",
headers: {
Authorization: bearer,
"Content-Type": "application/json"
}
})
.then(response => response.json())
.then(json => {});
});
};
Or you can use async/await.
req = async () => {
const first = await ( await fetch( "url", {
method: "POST",
headers: {
Authorization: bearer,
"Content-Type": "application/json",
},
body:
} ) ).json();
const second = await ( await fetch( `http://some.url${ first.id }` ),
{
method: "GET",
headers: {
Authorization: bearer,
"Content-Type": "application/json",
},
} ).json();
// use the variable second as your last result here.
};