const displayCharacters = async () => {
if(filteredCharacters !== 'default'){
const a = filteredCharacters.map(e => e.name);
const options = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ 'data' : a })
};
const b = await fetch("/image",options).then(res => res.json())
return b;
}else{
return "yikes";
}
}
console.log(displayCharacters());
I have this fetch request but when I log the results this is what i see :
Promise {<resolved>: "yikes"}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: "yikes"
I just want the promiseValue and not this whole thing around it. How do i do this?
the async function returns a promise instantly, without waiting for the promise to resolve. You may instead console.log inside the function:
const displayCharacters = async () => {
if(filteredCharacters !== 'default'){
const a = filteredCharacters.map(e => e.name);
const options = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ 'data' : a })
};
try {
const b = await fetch("/image",options).then(res => res.json());
console.log(b);
//the better practice is however, to do like:
const b = await fetch("/image",options)
const result = await b.json();
console.log(result );
}
catch(err) {
console.log(err);
}
}else{
console.log("yikes");
}
}
displayCharacters();
The best way that i know to use fetch goes something like this:
const displayCharacters = async () => {
if(filteredCharacters !== 'default'){
const a = filteredCharacters.map(e => e.name);
const options = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ 'data' : a })
};
const b = await fetch("/image",options)
.then(res => {
// Handle API Errors
if (!res.ok) {
throw Error(res.statusText);
}
// Return if no errors
return res.json();
})
// this is the data you want
.then(data => data)
// it will only reject on network failure or if anything prevented the request from completing
.catch(error => {
console.log(error.message)
});
return b;
}else{
return "yikes";
}
}
Basically you chain two thens and a catch to completely understand the response
- the first then checks for api level errors
- second then gets you the data
- catch is invoked in case when it is not able to reach the api itself like connection issues
Related
I have an await function() which waits for an external API. Usually, these APIs take 600ms to return data. But sometimes it's taking around 10 seconds. So how do I write a function so that if it takes more than 1 second, then break that function and resolve anyway (don’t wait for the API)
Here's the main function code which calls the API.
console.log("Before Await");
await fetchExternalAPI("data");
console.log("Continue if success or takes more than x seconds");
The actual function:
const fetch = require('node-fetch');
module.exports = async function fetchExternalAPI(data) {
try {
const response = await fetch("https://www.example.com/api/log", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
const returnData = await response.json();
console.log("Response: " + JSON.stringify(returnData))
return returnData
}
catch (e) {
console.log("Error: " + e)
return e
}
}
I want to return success fo the above function
if fetch is success
or if exceeded more than x seconds
Both should return success no matter the real output.
You can use AbortController to abort the fetch method, inside a setTimeout with 1sec, and if the fetch resolved before the setTimeout callback execute, then clearTimeout
const fetch = require('node-fetch');
module.exports = async function fetchExternalAPI(data) {
try {
let controller = new AbortController();
let timeId = setTimeout(() => {
controller.abort()
}, 1000)
const response = await fetch("https://www.example.com/api/log", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
signal: controller.signal
});
clearTimeout(timeId)
const returnData = await response.json();
console.log("Response: " + JSON.stringify(returnData))
return returnData
}
catch (e) {
console.log("Error: " + e)
return e
}
}
I think you need to use Axios.
npm i axios
than in body you have one property timeout.
const instance = await axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
You can add a promise in your call to resolve on time and reject if too long.
The following code has not been tested but that's the idea
const fetch = require('node-fetch');
module.exports = async function fetchExternalAPI(data) {
try {
const response = await fetch("https://www.example.com/api/log", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
await new Promise((resolve, reject) => {
setTimeout(reject, 50000));
resolve();
}).then(() => {
const returnData = await response.json();
console.log("Response: " + JSON.stringify(returnData))
return returnData
}).catch(() => {
return 'Took too long';
}));
}
catch (e) {
console.log("Error: " + e)
return e
}
}
I have this action in store
actions: {
testLogin(context, credentials) {
const loginService = new FetchClient();
let d = loginService.post('login', credentials);
console.log(d);
},
and this function in another class imported to store
async post(endpoint, params) {
await fetch(this.url + endpoint, {
'method': 'POST',
headers: this.headers,
body: JSON.stringify(params),
})
.then(response => {
return response.json();
})
.then( (data) => {
this.returnData = data.data;
})
.catch(error => {
console.log(error);
});
return this.returnData;
}
And I get Promise {<pending>} which I can extract data from inside the fetch class but can't access data if I'm in the store because it's a Promise not an object. How can I solve this?
Put the return statement inside the second then block:
async post(endpoint, params) {
await fetch(this.url + endpoint, {
'method': 'POST',
headers: this.headers,
body: JSON.stringify(params),
})
.then(response => {
return response.json();
})
.then( (data) => {
this.returnData = data.data;
return this.returnData;
})
.catch(error => {
console.log(error);
});
}
I would even recommend you use the following code for better legibility:
async post(endpoint, params) {
const response = await fetch(this.url + endpoint, {
'method': 'POST',
headers: this.headers,
body: JSON.stringify(params),
})
if (!response.ok) {
const message = `An error has occured: ${response.status}`;
throw new Error(message);
}
const resp_data = await response.json()
return resp_data.data
}
Then call your method like so:
post(endpoint, params)
.then(data => {// do something with data})
.catch(error => {
error.message; // 'An error has occurred: 404'
});
refer to this async/await guide
Can you try:
async testLogin(context, credentials) {
const loginService = new FetchClient();
let d = await loginService.post('login', credentials);
console.log(d);
}
As #Ayudh mentioned, try the following code:
async post(endpoint, params) {
try{
let response = await fetch(this.url + endpoint, {
'method': 'POST',
headers: this.headers,
body: JSON.stringify(params),
});
let data = await response.json();
this.returnData = data.data;
}catch(e){
console.log(e);
}
return this.returnData;
}
I'm struggling to return the synchronous results of the method below.
I call the method from a different method:
var result = this.getVendor(id)
console.log(result)
Here is the fetch method:
methods: {
async getData(id) {
const response = await fetch(`${API_URL}api/${id}`, {
method: "GET",
headers: {
authorization: `Bearer ${localStorage.token}`
}
})
.then(res => res.json())
.then(data => {
return data;
});
await response;
}
}
How do I return the results response of the getData() function to show in the console?
Async functions Always return a promise.
You can use the await syntax to return it properly.
async getData(id) {
const response = await fetch(`${API_URL}api/${id}`, {
method: "GET",
headers: {
authorization: `Bearer ${localStorage.token}`
}
})
const data = await response.json()
return data
}
You can access the data out of that function anywhere you call it.
let data = null
object.getData(2)
.then(x => {
data = x
})
Also if you are going to use async await make sure to use try and catch to handle any errors that come up.
async getData(id) {
try {
const response = await fetch(`${API_URL}api/${id}`, {
method: "GET",
headers: {
authorization: `Bearer ${localStorage.token}`
}
})
const data = await response.json()
return data
}
} catch(err) {
console.error(err)
}
I have stripe async code in my React app, and trying to add error handling in my code but have no idea how to handle it. i know how to do it with .then() but async/await is new to me
EDITED
added .catch() i got errors in network tab in response tab.
but i can log it to console?
submit = async () => {
const { email, price, name, phone, city, street, country } = this.state;
let { token } = await this.props.stripe
.createToken({
name,
address_city: city,
address_line1: street,
address_country: country
})
.catch(err => {
console.log(err.response.data);
});
const data = {
token: token.id,
email,
price,
name,
phone,
city,
street,
country
};
let response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}).catch(err => {
console.log(err.response.data);
});
console.log(response);
if (response.ok)
this.setState({
complete: true
});
};
thanks
Fetch detects only network errors. Other errors (401, 400, 500) should be manually caught and rejected.
await fetch("/charge/pay", headers).then((response) => {
if (response.status >= 400 && response.status < 600) {
throw new Error("Bad response from server");
}
return response;
}).then((returnedResponse) => {
// Your response to manipulate
this.setState({
complete: true
});
}).catch((error) => {
// Your error is here!
console.log(error)
});
If you are not comfortable with this limitation of fetch, try using axios.
var handleError = function (err) {
console.warn(err);
return new Response(JSON.stringify({
code: 400,
message: 'Stupid network Error'
}));
};
var getPost = async function () {
// Get the post data
var post = await (fetch('https://jsonplaceholder.typicode.com/posts/5').catch(handleError));
// Get the author
var response = await (fetch('https://jsonplaceholder.typicode.com/users/' + post.userId).catch(handleError));
if (response.ok) {
return response.json();
} else {
return Promise.reject(response);
}
};
You can either use try/catch just like normal, imperative programming:
try {
let response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
} catch(error) {
// Error handling here!
}
Or you can mix-and-match .catch() just like you do with promises:
let response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}).catch(function(error) {
// Error handling here!
});
Wrap your await with try catch.
try {
let response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
console.log(response);
} catch (error) {
console.log(error);
}
This works if server returns { message: "some error" } but I'm trying to get it to support res.statusText too:
const path = '/api/1/users/me';
const opts = {};
const headers = {};
const body = JSON.stringify({});
const token = localStorage.getItem('token');
if (token) {
headers.Authorization = `Bearer ${token}`;
}
try {
const res = await fetch(path, {
method: opts.method || 'GET',
body,
headers
});
if (res.ok) {
return await (opts.raw ? res.text() : res.json());
}
const err = await res.json();
throw new Error(err.message || err.statusText);
} catch (err) {
throw new Error(err);
}
async function loginWithRedirect(payload: {
username: string;
password: string;
}) {
const resp = await (await fetch(`${env.API_URL}/api/auth/login`, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(payload),
credentials: "include",
})).json();
if (resp.error) {
dispatch({type: "ERROR", payload: resp.error.message});
} else {
dispatch({type: "LOGIN", payload: resp});
}
}
If response.ok is false you can throw an error then chain catch method after calling your function as follows
async function fetchData(){
const response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
if(!response.ok){
const message = `An error occured: ${response.status}`;
throw new Error(message);
}
const data = await response.json();
return data;
}
fetchData()
.catch(err => console.log(err.message));
I write promise function for using fetch in async await.
const promisyFetch = (url, options) =>
new Promise((resolve, reject) => {
fetch(url, options)
.then((response) => response.text())
.then((result) => resolve(result))
.catch((error) => reject(error));
});
By the way i can use it easly in async with try catch
const foo = async()=>{
try {
const result = await promisyFetch('url' requestOptions)
console.log(result)
} catch (error) {
console.log(error)
}
}
It was simple example, you could customize promisyFetch function and request options as you wish.
const data = {
token: token.id,
email,
price,
name,
phone,
city,
street,
country
};
axios
.post("/charge/pay", data)
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err.response.data);
});
I have a react-native app where I do a call to an api where it should return the JSON but I'm just having undefined.
export function fetchFromAPI() {
AsyncStorage.getItem('#token', (errToken, token) => {
let token = null;
const requestBody = { token: token };
return fetch(url, {
method: 'POST',
body: JSON.stringify(requestBody)
})
.then((response) => response.json())
.then((responseJSON) => {
console.log(responseJSON); // <-- this shows the correct JSON data
return responseJSON;
}).catch((error) => {
// console.error(error);
});
});
}
I also call that funcion like this:
const apiData = fetchFromAPI();
If I do console.log() inside the fetch function, it returns the JSON data but if I do to apiData, it just gets undefined.
Does anyone has some idea why its like this, I'm doing something wrong?
You can use Promise to get response from fetchFromAPI function, like
export function fetchFromAPI() {
return new Promise((resolve, reject) => {
AsyncStorage.getItem('#token', (errToken, token) => {
let token = null;
const requestBody = {
token: token
};
return fetch(url, {
method: 'POST',
body: JSON.stringify(requestBody)
})
.then((response) => response.json())
.then((responseJSON) => {
console.log(responseJSON); // <-- this shows the correct JSON data
resolve(responseJSON);
}).catch((error) => {
reject(error);
});
});
});
}
When calling the fetchFromAPI, use await, like
const apiData = await fetchFromAPI();
You can also use .then to capture the response and store it in the state, like
fetchFromAPI.then((data) => {
// use data here
});
Hope this will help!
First, you need to return the Promise created by getItem:
export function fetchFromAPI() {
return AsyncStorage.getItem('#token', (errToken, token) => {
let token = null;
const requestBody = { token: token };
return fetch(url, {
method: 'POST',
body: JSON.stringify(requestBody)
})
.then((response) => response.json())
.then((responseJSON) => {
console.log(responseJSON); // <-- this shows the correct JSON data
return Promise.resolve(responseJSON); // <-- this wraps the JSON into a Promise
}).catch((error) => {
// console.error(error);
});
});
}
Then you need to call the function like this:
fetchFromAPI().then(apiData => {...