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.
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,
// ...
}
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
I have a helper function that uses FETCH to pull data from an API. I'm trying to set the response of the fetch request to my state using setState() but it keeps returning undefined. Here is my helper function: (I realize I'm exposing my keys on the front end but I will adjust if I ever deploy to production)
const authCode = {
async getAuthCode() {
const authCodeMatch = window.location.href.match(/code=([^&]*)/)[1];
await fetch(`https://id.twitch.tv/oauth2/token?client_id=${TWITCH_ID}&client_secret=${TWITCH_SECRET}&code=${authCodeMatch}&grant_type=authorization_code&redirect_uri=${TWITCH_CB}`, {
method: 'POST',
mode: 'cors',
'Access-Control-Allow-Origin':'*',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
})
.then(response =>
response.json()
)
.then(data => {
console.log(data.access_token);
fetch(`https://api.twitch.tv/helix/users?id=43691`, {
method: 'GET',
mode: 'cors',
'Access-Control-Allow-Origin':'*',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Client-ID': TWITCH_ID,
'Authorization': 'Bearer ' + data.access_token
}
})
.then(response => response.json())
.then(newdata => {
console.log(newdata);
if (!newdata.data) {
return [];
}
//console.log(newdata.data[0].view_count);
return newdata.data.map(views => ({
view_count: views.view_count
}))
})
})
}
Everything logs to the console fine so I'm pretty sure I'm mapping through the correct array to parse the data. In any case, here is the returned object in console as well as my component code. In my profile component it just pushes undefined to my state:
// Console response
data: Array(1)
0:
broadcaster_type: "partner"
description: ""
display_name: "Faker"
id: "43691"
login: "faker"
offline_image_url: "https://static-cdn.jtvnw.net/jtv_user_pictures/7d76e34d-3ee3-42c0-a46b-e320d37fcde6-channel_offline_image-1920x1080.jpeg"
profile_image_url: "https://static-cdn.jtvnw.net/jtv_user_pictures/b2eb8a23-d6ad-45aa-bd8e-062133b64452-profile_image-300x300.png"
type: ""
view_count: 81769581
__proto__: Object
length: 1
__proto__: Array(0)
Component
export default class Profile extends Component {
constructor(props) {
super(props);
this.state = {
viewData: []
}
this.handleNewPost = this.handleNewPost.bind(this);
}
handleNewPost () {
authCode.getAuthCode().then(viewcountResults => {
this.setState({viewData: viewcountResults})
})
}
render() {
return (
<div>
<Container>
<div className='mt-5'>
<Button color='success' size='lg' onClick={this.handleNewPost}>
Post Data
</Button>
</div>
<div>
{this.state.viewData.view_count}
</div>
</Container>
</div>
)
}
Thanks for any help!
Your function getAuthCode isn't returning a Promise containing the data you're wanting to receive. Also, you can greatly clean up that code by using await instead of a mixture of await and callbacks.
const authCode = {
async getAuthCode() {
const authCodeMatch = window.location.href.match(/code=([^&]*)/)[1];
let response = await fetch(`https://id.twitch.tv/oauth2/token?client_id=${TWITCH_ID}&client_secret=${TWITCH_SECRET}&code=${authCodeMatch}&grant_type=authorization_code&redirect_uri=${TWITCH_CB}`, {
method: 'POST',
mode: 'cors',
'Access-Control-Allow-Origin':'*',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
console.log(data.access_token);
response = await fetch(`https://api.twitch.tv/helix/users?id=43691`, {
method: 'GET',
mode: 'cors',
'Access-Control-Allow-Origin':'*',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Client-ID': TWITCH_ID,
'Authorization': 'Bearer ' + data.access_token
}
});
const newData = await response.json();
console.log(newdata);
if (!newdata.data) {
return [];
}
return newdata.data.map(views => ({
view_count: views.view_count
}));
}
}
I have the following code below. What i want to do is handle the network error case and the returned HTTP server error cases separately.
fetch("$imageUploadUrl", {
method: "POST",
mode: "same-origin",
cache: "no-store",
credentials: "same-origin",
redirect: "error",
referrer: "origin",
body: formData
}).catch(function(error) {
failure("There was an error while uploading the image");
}).then(function(response) {
if (response.ok){
return Promise.resolve(response.json());
} else {
return Promise.reject(response.text())
}
}).then(function(result) {
success(result.location);
}).catch(function(errorText) {
return failure (errorText);
})
However, unlike Promise.resolve(), Promise.reject() does not wait to resolve the promise from response.text() before returning it. I have managed to receive a resolved promise by adding async/await like that:
fetch("$imageUploadUrl", {
method: "POST",
mode: "same-origin",
cache: "no-store",
credentials: "same-origin",
redirect: "error",
referrer: "origin",
body: formData
}).catch(function(error) {
failure("There was an error while uploading the image");
}).then(async function(response) {
if (response.ok){
return Promise.resolve(response.json());
} else {
return Promise.reject(await response.text())
}
}).then(function(result) {
success(result.location);
}).catch(function(errorText) {
failure(errorText);
});
Is this the only way to reach my goal?
I have also tried doing this:
fetch("$imageUploadUrl", {
method: "POST",
mode: "same-origin",
cache: "no-store",
credentials: "same-origin",
redirect: "error",
referrer: "origin",
body: formData
}).catch(function(error) {
failure("There was an error while uploading the image");
}).then(function(response) {
if (response.ok){
return Promise.resolve(response.json());
} else {
return Promise.reject(response.text())
}
}).then(function(result) {
success(result.location);
}).catch(function(textPromise) {
return textPromise;
}).then(function(text) {
console.log(text);
})
But the final then with the console.log is called always, even when i call Promise.resolve() in the code above it, as it was attached on the promise from fetch function itself. Do you know why this happens.
You can wait for the promise, then reject it:
return response.text().then(text => Promise.reject(text));
And what about this version:
const options = {
method: 'POST',
mode: 'same-origin',
cache: 'no-store',
credentials: 'same-origin',
referrer: 'origin',
body: formData
}
async function parseResponse (response) {
try {
success(await response.json())
} catch () {
failure(await response.text())
}
}
function parseError (err) {
failure(`Error uploading file: ${err}`)
}
fetch('$imageUploadUrl', options)
.then(parseResponse)
.catch(parseError)
I am using Fetch-node for a GET to a service.
const response = await fetch("MY URL", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
timeout: 5000,
}).then(res => res.json()).then(json => console.log(json));
console.log(response);
I log the result in the second console.log() then and everything is fine.
However, when it comes to the second console.log() the response is undefined.
What I need is whatever is logged in the second to be stored in the response.
Is there anything wrong with what I am doing?
As mentioned, you're not returning a value for response, therefore it won't be equal to anything. You could return the JSON from your final then, or if you felt it was any cleaner, just await both instead of using .then at all.
const response = await fetch("MY URL", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
timeout: 5000
});
const json = await response.json();
console.log(json);
You should return your value in your function.
const response = await fetch("MY URL", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
timeout: 5000,
}).then(res => res.json()).then(json => {
// do something
return json //<--- return a value
});
console.log(response);
You can write the whole code with async/await. In your code you mixed promise and async/await syntax, and forgot to return json from last .then() function.
This is how I write the code:
async function fetchData() {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
timeout: 5000,
})
const data = await response.json();
console.log(data);
}
fetchData();