I'm having a problem with my API request that always fails after page load. Don't really know where Im wrong.
Here's my request and I call it when I interact with handleOpen function.
const stock = {
method: 'GET',
url: 'https://morningstar1.p.rapidapi.com/live-stocks/GetRawRealtimeFigures',
params: {Mic: props.mic, Ticker: clickedElement.ticker},
headers: {
'x-rapidapi-key': 'XXX',
'x-rapidapi-host': 'morningstar1.p.rapidapi.com'
}
}
const getStock = async () => {
try {
const res = await axios.request(stock);
return res.data;
}
catch (error) {
setOpen(false);
console.error("catch api error: ", error);
}
}
const handleOpen = name => {
let findClickedStock = props.stocksArray.find(item => item.ticker === name)
setClickedElement(findClickedStock)
getStock().then((dataFromStockApi) => {
let combined1 = { ...dataFromStockApi, ...findClickedStock }
setStockObject(combined1);
});
setOpen(true);
};
ERROR:
It's because your Ticker parameter is empty.
When you create "stock", clickedElement.ticker is undefined.
Do this:
// pass name in as a parameter
getStock(name).then(...)
Make getStock like like this:
const getStock = async (ticker) => {
try {
const res = await axios.request({
method: 'GET',
url: 'https://morningstar1.p.rapidapi.com/live-stocks/GetRawRealtimeFigures',
params: {Mic: props.mic, Ticker: ticker},
headers: {
'x-rapidapi-key': 'XXX',
'x-rapidapi-host': 'morningstar1.p.rapidapi.com'
}
});
return res.data;
}
catch (error) {
setOpen(false);
console.error("catch api error: ", error);
}
}
Related
I've this code into pages folder on my NextJS environment. It gets data calling an external API Rest, and it's working because the console.log(response); line show me by console the Json API response. The problem I've is that I get this error in browser:
TypeError: Cannot read property 'json' of undefined
Corresponding with this line code:
const data = await res.json();
This is the complete file with the code:
import React from "react";
import fetch from "node-fetch";
const getFetch = async (invoicesUrl, params) => {
fetch(invoicesUrl, params)
.then((response) => {
return response.json();
})
.then((response) => {
console.log(response);
})
.catch((err) => {
console.log(err);
});
};
export const getServerSideProps = async () => {
const invoicesUrl = "https://192.168.1.38/accounts/123456";
const params = {
method: "get",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
};
const res = await getFetch(invoicesUrl, params);
const data = await res.json();
console.log("Data Json: ", data);
return { props: { data } };
};
This is the Json API response that I see by console:
{
account: [
{
id: '7051321',
type: 'probe',
status: 'open',
newAccount: [Object],
lastDate: '2020-07-04',
taxExcluded: [Object],
totalRecover: [Object],
documentLinks: []
},
]
}
Any idea how can I solve it?
Thanks in advance.
UPDATE
Here the code working good:
import React from "react";
import fetch from "node-fetch";
const getFetch = async (invoicesUrl, params) => {
return fetch(invoicesUrl, params);
};
export const getServerSideProps = async () => {
const invoicesUrl = "https://192.168.1.38/accounts/123456";
const params = {
method: "get",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
};
try {
const res = await getFetch(invoicesUrl, params);
const data = await res.json();
console.log("Data JSON: ", data);
return { props: { data } };
} catch (error) {
console.log("Data ERROR: ", error);
}
};
There are a couple of things you have to change.
const getFetch = async (invoicesUrl, params) => {
fetch(invoicesUrl, params)
.then((response) => {
return response.json();
})
.then((response) => {
console.log(response);
return response; // 1. Add this line. You need to return the response.
})
.catch((err) => {
console.log(err);
});
};
export const getServerSideProps = async () => {
const invoicesUrl = "https://192.168.1.38/accounts/123456";
const params = {
method: "get",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
};
const data = await getFetch(invoicesUrl, params);
// const data = await res.json(); 2. Remove this you have already converted to JSON by calling .json in getFetch
console.log("Data Json: ", data); // Make sure this prints the data.
return { props: { data } };
};
You have return statement in wrong place.
When the function is expecting a return. You need to return when the statements are executed not inside the promise then function because it is an async callback function which is not sync with the statement inside getFetchfunction. I hope i have made things clear. Below is the code which will any how return something
import React from "react";
import fetch from "node-fetch";
const getFetch = async (invoicesUrl, params) => {
return fetch(invoicesUrl, params);
};
export const getServerSideProps = async () => {
const invoicesUrl = "https://192.168.1.38/accounts/123456";
const params = {
method: "get",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
};
try{
const res = await getFetch(invoicesUrl, params);
console.log("Data Json: ", res);
}catch(error){
console.log("Data Json: ", error);
}
return { props: { res } };
};
I am new to react native and making service call for the first time. My problem is service call is not going and getting warning like
Possible unhandled Promise Rejection, Reference error: response is not defined.
I am trying to hit loginUser function.
Api.js
const BASE_URL = "http://localhost:8200";
export const api = async (url, method, body = null, headers = {}) => {
try {
const endPoint = BASE_URL.concat(url);
const reqBody = body ? JSON.stringify(body) : null;
const fetchParams = {method, headers};
if((method === "POST" || method === "PUT") && !reqBody) {
throw new Error("Request body required");
}
if(reqBody) {
console.log("ReQBody--->"+reqBody);
fetchParams.headers["Content-type"] = "application/json";
fetchParams.body = reqBody;
}
const fetchPromise = await fetch(endPoint, fetchParams);
const timeOutPromise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("Request Timeout");
}, 3000);
});
const response = await Promise.race([fetchPromise, timeOutPromise]);
return response;
} catch (e) {
return e;
}
}
export const fetchApi = async (url, method, body, statusCode, token = null, loader = false) => {
console.log("In FetchAPi Function");
try {
const headers = {}
const result = {
token: null,
success: false,
responseBody: null
};
if(token) {
headers["securityKey"] = token;
}
const response = await api(url, method, body, headers);
console.log("fetchApi-->>"+response);
if(response.status === statusCode) {
result.success = true;
let responseBody;
const responseText = await response.text();
try {
responseBody = JSON.parse(responseText);
} catch (e) {
responseBody = responseText;
}
result.responseBody = responseBody;
return result;
}
let errorBody;
const errorText = await response.text();
try {
errorBody = JSON.parse(errorText);
} catch (e) {
errorBody = errorText;
}
result.responseBody = errorBody;
console.log("FetchApi(Result)--->>"+result);
throw result;
} catch (error) {
return error;
}
}
auth.actions.js
export const loginUser = (payload) => {
console.log("In LoginUser function2");
return async (dispatch) => {
<-----**I am not able to enter into this block**------>
try {
dispatch({
type: "LOGIN_USER_LOADING"
});
console.log("In LoginUser function3");
const response = await fetchApi("/login", "POST", payload, 200);
if(response.success) {
dispatch({
type: "LOGIN_USER_SUCCESS",
});
dispatch({
type: "AUTH_USER_SUCCESS",
token: response.token
});
dispatch({
type: "GET_USER_SUCCESS",
payload: response.responseBody
});
return response;
} else {
throw response;
}
} catch (error) {
dispatch({
type: "LOGIN_USER_FAIL",
payload: error.responseBody
});
return error;
}
}
}
In console log, I can't see anything in network tab. In the android emulator, the mentioned warning has come.
My console tab
I see that your BASE_URL is served using an http endpoint. You can only make requests to https endpoints from react native projects. A possible workaround is to use ngrok. Just download it and run ./ngrok http 8200 since your port number is 8200. It will expose an HTTPS endpoint and replace your BASE_URL with that link and try fetching the data again.
I use the following code to make API calls. See if you can integrate it in your code. it is quite simple:
In a class called FetchService:
class FetchService {
adminAuth(cb, data) {
console.log('here in the fetch service');
return fetch(
baseURL + "login",
{
method: "POST",
headers: {
Accept: "application/json",
},
body: data
}
)
.then((response) => response.json())
.then(responsej => {
cb(null, responsej);
})
.catch(error => {
cb(error, null);
});
}
}
export default FetchService;
Then call it from your component using:
import FetchService from './FetchService';
const fetcher = new FetchService;
export default class LoginScreen extends React.Component {
fetchData() {
const data = new FormData();
data.append('username',this.state.username);
data.append('password',this.state.password);
fetcher.wastereport((err, responsej) => {
if(err) {
//handle error here
} else {
//handle response here
}
}, data);
}
}
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'm trying to use asyncstorage in my react native app.The problem is the server response I'm getting takes some delay so I want to wait for the response then I want to use that responseData.user_id to be saved in my app.I'm using nodejs as backend and mysql db.So after user registration I'm inserting it to db at the same time I've written another query for fetching their user_id (PK).So this responseData is getting to client and I'm trying to take that user_id from the response.So I've written something like this
onPressRegister = async () => {
try {
let response = await fetch('http://192.168.1.2:3000/users/registration', {
method: 'POST',
headers: {
'Accept': 'applictaion/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
contact: this.state.contact,
password: this.state.password,
})
});
let responseData = await response.json();
if (responseData) {
try {
Action.firstScreen();
await AsyncStorage.setItem('userid', JSON.stringify(responseData.userData.phone_no));
}
catch (e) {
console.log('caught error', e);
}
}
} catch (error) {
console.error(error)
}
}
And in my next screen I'm accessing the userid like this.And passing it the next API call like this.
getUserId = async () => {
let userId = await AsyncStorage.getItem('userid');
return userId;
}
onPressYes = (workType) => {
this.getUserId().then((userId) => {
this.setState({userId:userId})
})
fetch('http://192.168.1.2:3000/users/user_request',{
method:'POST',
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
workType,
phone:this.state.userId
})
})
.then(response => response.json())
.then((responseData) => {
this.setState({
data:responseData
});
});
}
But this is the error I'm getting.
Try this:
onPressRegister = async () => {
try {
let response = await fetch('http://192.168.1.6:3000/users/registration', {
method: 'POST',
headers: {
'Accept': 'applictaion/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
contact: this.state.contact,
password: this.state.password,
})
});
let responseData = await response.json();
if (responseData) {
try {
await AsyncStorage.setItem('userid', JSON.stringify(responseData.user_id));
}
catch (e) {
console.log('caught error', e);
}
}
} catch (error) {
console.error(error)
}
}
To access the value in some other component:
getUserId = async () => {
let userId = await AsyncStorage.getItem('userid');
return userId;
}
componentWillMount() {
this.getUserId().then((userId) => {
console.log(userId);
})
}
i am having exsiting service to make api call through axios in my react app,which i think is limited to one api request at a time,i wanted to make multiple request using axios.all,but i am not able to find way to modify the service,see below is the code
As in Action.js you can see that i combine two request which is wrong i guess so,please help me how to combine two request using axios.all,and please suggest api service implementation is correct or what can i do to improve it
APIService.js
import axios from 'axios';
import apiConfig from './apiConfig';
import UserSession from './userSession';
import history from '../utils/history/history';
const session = sessionStorage;
var axiosConfig = axios.create({
baseURL: apiConfig.baseUrl,
headers: {
Authorization: sessionStorage.getItem('token') != null ?
`Bearer ${sessionStorage.getItem('token')}` : null,
Accept: 'application/json',
'Content-Type': 'application/json'
},
timeout: 20000,
responseType: 'json'
});
axiosConfig.interceptors.request.use((config) => {
config.headers.Authorization =
sessionStorage.getItem('token') != null ? `Bearer
${sessionStorage.getItem('token')}` : null;
return config;
},(error) => Promise.reject(error));
const apiService = function(options) {
const onSuccess = function(response) {
if (response.status === 201) {
return Promise.resolve(
Object.assign(
{},
{
message: response.statusText
}
)
);
} else if (response.status === 200) {
if ((response.data && response.data !== null) || response.data !==
undefined || response.data !== '') {
return response.data;
} else {
return Promise.resolve(
Object.assign(
{},
{
message: response.statusText
}
)
);
}
} else if (response.data.length < 1) {
return Promise.reject(
Object.assign(
{},
{
message: 'No Data'
}
)
);
} else {
return response.data;
}
};
const onError = function(error) {
if (error.response) {
if (error.response.status === 401) {
sessionStorage.removeItem('token');
window.location = '/login';
return Promise.reject(error.response);
} else if (error.response.status === 404) {
return Promise.reject(
Object.assign(
{},
{
message: error.response.statusText
}
)
);
} else if (error.response.status === 500) {
return Promise.reject(
Object.assign(
{},
{
message: error.response.statusText
}
)
);
} else {
return Promise.reject(error.response.data);
}
} else if (error.request) {
// The request was made but no response was received
return Promise.reject(
Object.assign(
{},
{
message: error.message
}
)
);
//return Promise.reject(error.message);
} else {
// Something else happened while setting up the request
// triggered the error
return Promise.reject(
Object.assign(
{},
{
message: error.message
}
)
);
}
};
return axiosConfig(options).then(onSuccess).catch(onError);
};
export default apiService;
Request.js
import apiService from '../apiService';
export const FirstRequest = () => {
return apiService({
url: 'FirstURL',
method: 'get',
});
};
export const SecondRequest = () => {
return apiService({
url: 'SecondURL',
method: 'get',
});
};
Action.js
export const SomeHandler = () => (dispatch) => {
dispatch({
type: API_REQUEST
});
FirstRequest()
.then((res) => {
dispatch({
type: API_SUCCESS
});
SecondRequest().then((res) => {
dispatch({
type: API_SUCCESS
});
dispatch({ type: VIEW1, payload: res });
dispatch({ type: VIEW2, payload: res });
}).catch((err) => {
dispatch({
type: API_FAILURE,
payload: err
});
});
})
.catch((err) => {
dispatch({
type: API_FAILURE,
payload: err
});
});
};
This is not related to axios at all. You can combine two async functions together in an action method, using async library:
async.parallel([
getUsers,
getComments
],
function(err, results) {
// the results array will equal to [[], {'x': 'y'}] even though
// the second function had a shorter timeout.
// dispatch here
});
function getUsers(callback) {
callback(null, [])
}
function getComments(callback) {
callback(null, {'x': 'y'})
}
First off, not sure you want to do this in your componentWillMount, because your component will not render until all this is done, it's better to have it in componentDidMount and have some default states that will update once done with these requests. Second, you want to limit the number of setStates you write because they might cause additional re-renders, here is a solution using async/await:
async componentDidMount() {
const firstRequest = await axios.get(URL1);
const secondRequest = await axios.get(URL2);
const thirdRequest = await axios.get(URL3);
this.setState({
p1Location: firstRequest.data,
p2Location: SecondRequest.data,
p3Location: thirdRequest.data,
});
}
i'm working this way. you can use this
const token_config = {
headers: {
'Authorization': `Bearer ${process.env.JWD_TOKEN}`
}
}
const [ res1, res2 ] = await Axios.all([
Axios.get(`https://api-1`, token_config),
Axios.get(`https://api-2`, token_config)
]);
res.json({
info: {
"res_1": res1,
"res_2": res2
}
});