I am trying to put fetch functions into a separated file, so I can organise these API fetch easily. However, when I try to fetch and return the data, it gives me null or an unexpected json object. Here is part of my src:
//api.js
export async function LoginAPI(username, password) {
const url = baseURL + "/login/";
var params = {username: username, password: md5.hex_md5(password)};
let response = await fetch(url, {
method: 'POST',
headers: {'Accept': 'application/json','Content-Type': 'application/x-www-form-urlencoded'},
body: JSON.stringify(params)
});
return await fetch(url, {
method: 'POST',
headers: header,
body: JSON.stringify(params)
})
.then((res) => res.text())
.then((text) => text.length ? JSON.parse(text) : {})
.catch((error) => {
throw error;
});
};
Here is the another file.
//index.js
var Login = React.createClass({
onPress_login: function() {
var value = this.refs.form.getValue();
if (value) {
result = LoginAPI(value.username, value.password);
console.log(result);
} else {
this.AlertDialog.openDialog();
}
},
render() {
return (
(...)
<Button onPress={this.onPress_login}>
<Text>Login</Text>
</Button>
The fetch is working, it is communicating with the server. However, the console log returns me this at the first place
Promise _45: 0_54: null _65: null _81: 1 __proto__: Object
I am assuming that the result log in the console at the first place is not the await result (the actual response from server, but an object of fetch response). I tried to search out methods online but I can't find any post/blog/article saying how to do fetch as a function call.
Is there any way to do like swift, LoginAPI(username, password, callback: {...}) please?
The problem is that you're are making an async function and not waiting for the response, the you see that kind of console log.
Try this:
result = await LoginAPI(value.username, value.password);
Let me know if this was your problem.
Related
I am attempting to render data which was retrieved from my backend server.
The connection works fine and i'm able to retrieve a response.. My problem is that once I have loaded the information into my state-array, I cannot seem to access the properties within.
My useState array filled with the API request's data:
my backend's method i'm calling from my react program:
router.route("/api/issues").get(getAllIssues);
the route is calling the following function:
export const getAllIssues = async (
req: Request,
res: Response
): Promise<void> => {
try {
const issues: IssueInterface[] = await Issue.find({});
res.status(200).json({ issues });
} catch (err) {
throw err;
}
};
fetching the data from the api:
function Issues({ }: Props) {
const [issuesList, setIssuesList] = useState<IssueInterface[]>([]); // we retrieve from DB issues - we need it to look the same object's structure
useEffect(() => {
try {
axios({
method: 'get',
url: 'http://localhost:8001/api/issues',
headers: { 'Content-type': "application/json" }
}).then((response) => {
console.log(typeof (response))
const issuesStringified = JSON.stringify(response.data)
console.log("stringified: " + issuesStringified)
console.log(issuesList)
})
} catch (err) {
console.log("error : " + err);
}
}, [])
now my attempt to render parts of the array by using the following return function:
return (
<Stack>
<div>
{hasLoaded ? issuesList.map((issue: IssueInterface) => <div><h1>company: {issue.company_name}</h1></div>) : <></>}
</div>
</Stack>
)
provides the following outcome:
as if, it is unable to access the properties of each element.
any idea what am I doing wrong here?
regards! :_)
In my ReactNative app, I'm trying to come up with a nice pattern to read the access_token I store in AsyncStorage and use it in a fetch call.
In other words, I want to create a pattern that uses some type of wrapper that makes sure that the fetch call always has the access_token it needs. So execution order should always be:
Invoke Fetch Call -> Get Token from AsyncStorage and Prep Header -> Execute Fetch Call
I came up with the following code but it looks like I'm having problems with the Async part of AsyncStorage and my fetch calls are going out without the token.
Here's my fetch call:
export const someApiCall = (request) => {
const url = 'https://myapi.com/add';
return (dispatch) => fetch(url, fetchOptionsPost(request))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
}
Here, I'm using a helper function to prepare the headers, etc. Here's what the fetchOptionsPost() looks like:
export const fetchOptionsPost = (request) => {
getAccessToken()
.then(token => {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
},
body: JSON.stringify(request)
}
});
};
And the getAccessToken() function simply reads it from AsyncStorage as below:
export const getAccessToken = async () => {
return await AsyncStorage.getItem("access_token");
}
This pattern is NOT working and API calls are going out without a token.
I also want to mention that if I hard-code the token inside my fetchOptionsPost() method, everything works fine. Clearly, the issue here is that the fetchOptionsPost() is not returning anything.
What can I do to make sure that I will ALWAYS have my token in my fetchOptionsPost?
you could add token call inside someApiCall function .And also create the options on inside the function . function was async so fetch only run after get token result
Updated
const fetchOptionsPost = (token) =>{
return ({
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
}
})
}
export const someApiCall = async(request) => {
const token = await AsyncStorage.getItem("access_token");
const url = 'https://myapi.com/add';
fetch(url, fetchOptionsPost(token))
.then(response=>response.json())
.then((data)=>{
// call the dispatch here
})
}
Why use async inside on main function
AsyncStorage only have async callback. if you are set the AsyncStorage as separate function you should call async for the both function.Thats why i added with in parent async function and pass the token to fetchOptionsPost
Here's what I've come up with which seems to work fine. I still would appreciate any suggestions or improvements to this code.
First, here's what my fetch call looks like now. I wrapped it inside the getAccessToken() function which is an async call but because I'm using redux-thunk, I'm able to do this.
export const someApiCall = (request) => {
const url = 'https://myapi.com/add';
return (dispatch) => getAccessToken()
.then(token => {
fetch(url, fetchOptionsPost(request, token))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
})
}
I slightly changed my fetchOptionsPost() helper function which now accepts the token. It's also a bit more robust now. If it doesn't get a token, it simply omits the Authorization part in the header. I opted for this approach as some calls to my API backend do not require authentication. Also the isValidString() is another helper validation function I created to make sure I do get a valid string. It returns a TRUE or FALSE response based on the string value inputed:
export const fetchOptionsPost = (data, token = null) => {
if (isValidString(token)) {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
},
body: JSON.stringify(data)
}
} else {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}
}
};
And finally, the getAccessToken() function which didn't really change but here it is:
export const getAccessToken = async () => {
return await AsyncStorage.getItem("access_token");
}
As I said, I'd appreciate any comments or suggestions on further improving this code.
Hope this is useful to others.
Use Async and await method and get the token before each call.
async ()=>{
let token =await getTokenFromLocal();
return (dispatch) => fetch(url, fetchOptionsPost(request))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
}
I have been trying to make a login page in reactjs but it's throwing me an error in console like
SyntaxError: Unexpected token r in JSON at position 0 but I got 200 status code in network tab and also I'm getting "redirect" in both response and preview tab under the network tab.
I tried the same code(except it was if(response.ok) this time) with another server of my friend and it successfully redirects it to another page
This is the code that I've been trying: is response.data not correct for reactjs?
performLogin = async () => {
var body = {
password: this.state.password,
email: this.state.email
};
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify(body)
};
const url = "/api/authenticate";
try {
const response = await fetch(url, options);
const result = await response.json();
console.log(response); //nothing is showing in console for this statement
if (response.data == "redirect") {
this.props.history.push(`/verifyOtp/${this.state.email}`);
} else {
console.log("login failed");
window.alert("login failed");
}
} catch (error) {
console.error(error);
}
};
edit: I also tried it in postman and it gives "redirect" as response in postman so the api must be working fine
Your problem is in this line
const result = await response.json();
Your response is ok, everything is ok, but when you try to do response.json() and the response from the request isn't a valid json (maybe just a normal text), it will give you that error.
Because response can be a text or a json, you need to do some checking. Where is how to check if response is a json
This is kind of bad because on every request you will need to do this type of checking (transform it to text, try to parse, bla bla...), so What I recommend it you to use something better than fetch.
Axios is very good because it already do that checking.
For your example:
performLogin = async () => {
var body = {
password: this.state.password,
email: this.state.email
};
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify(body)
};
const url = "/api/authenticate";
try {
const response = await fetch(url, options); // Fetch the resource
const text = await response.text(); // Parse it as text
const data = JSON.parse(text); // Try to parse it as json
// Do your JSON handling here
} catch(err) {
// This probably means your response is text, do you text handling here
}
}
I am trying to use the requestjs package to post data and wait for a response. But I the body response is always undefined.
var request = require('request');
request({
method: "POST",
baseUrl: "https://255.255.255",
uri: "/login",
form: {
username: "username",
password: "password",
autologin: "true"}},
function(body, msg, err){
console.log(body); console.log(msg);
})
Edit: Again, the undefined body was caused by a privacy policy.
The format for the callback is (err,response,body); maybe that is why you are getting a empty body and response.
You can refer here for details.
I think you are getting confused with Promise and non-promise request package. As per your example, $ajax returns Promiseified response and you directly get the data from the response of the ajax request. You are expecting that request package should also give you data directly, which is not correct.
Actually, you can solve your issue in two ways:
Sol. 1:
Use proper callback function arguments and you must get data in the third argument of the callback function. Such as:
var request = require('request');
request({
method: "POST",
baseUrl: "https://255.255.255",
uri: "/login",
form: {
username: "username",
password: "password",
autologin: "true"
}
},
function (error, httpResponse, body) {
if (error) {
console.error(error);
}
console.log(httpResponse.statusCode);
console.log(body);
});
Sol. 2:
Use request-promise NPM package (download it from here) and get pomisified response. For example:
var request = require('request-promise');
const getData = async () => {
return new Promise((resolve, reject) => {
const options = {
method: "POST",
baseUrl: "https://255.255.255",
uri: "/login",
form: {
username: "username",
password: "password",
autologin: "true",
resolveWithFullResponse: true, // Returns full response. To get only data don't use this property or mark it false.
}
};
// Get whole Response object.
const response = await request(options);
// Returns the Promise.Resolve or Reject based on response.
if (response.statusCode < 200 || response.statusCode > 300) {
const errorMsg = 'Error occurred while POSTing the request. Got status: ' + response.status;
console.error(errorMsg);
// Reject the promise. Should be caught.
return reject(errorMsg);
}
const responseBody = response.body;
console.log(responseBody);
// Return the response.
return resolve(responseBody);
})
}
Above implementation will return a promise for the method getData() being called.
NOTE: The statement const response = await request(options); will return whole response object if resolveWithFullResponse: true, is used in the options JSON object. If you need only response body or data don't mention resolveWithFullResponse property in the options or assign value false to it. By default the value of resolveWithFullResponse is false.
I have a login form and I am able to post the form values. After the successful POST request, I get authentication token returned from the API. I need to save this token for future reference in local storage. For saving this auth token I am using AsyncStorage. I used AsyncStorage.setItem(STORAGE_KEY, responseData.auth_token); setItem method to save the data.
If I console log this by :
console.log(AsyncStorage.setItem(STORAGE_KEY));
it returns as promise object like this
Promise {_45: 0, _81: 0, _65: null, _54: null}
_45
:
0
_54
:
null
_65
:
"efcc06f00eeec0b529b8"
_81
:
1
__proto__
:
Object
how can I get the exact value from the AsyncStorage.getItem method?
This is my fetch method
fetch('http://54.255.201.241/drivers', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
first_name: this.state.firstName,
mobile_number: this.state.mobileNumber,
vehicle_number: this.state.vehicleNumber,
vehicle_type_id: 1,
})
}).then((response) => response.json()).then((responseData) => {
if (JSON.stringify(responseData.mobile_number) == (this.state.mobileNumber))
{
AsyncStorage.setItem(STORAGE_KEY, responseData.auth_token);
console.log(AsyncStorage.getItem(STORAGE_KEY));
this.props.navigator.push({id: 'Otp'})
}
else
{
Alert.alert("SignUp Failed","Mobile number already taken.")
}
})
.done();
BTW in documentation they have used await. I tried using that but the pages are not loading.Here with attached the screenshot.
using Async/Await :
async _getStorageValue(){
var value = await AsyncStorage.getItem('ITEM_NAME')
return value
}
You have to call as
getUserToken().then(res => {
console.log(res);
});
Since this is an async call.
This is how I usually manage to get the Value from The Local Storage:
const getItemFromStorage = async () => {
try {
await AsyncStorage.getItem('ITEM_NAME', (error: any, result: any) => {
if (result) {
console.log(result);
}else{
console.log(JSON.stringfy(error));
}
});
} catch (error) {
console.log(error);
}
}