Strange Response Interpretation From Server using React Native - javascript

I am using "React Native" in order to create an application for that acts as a web server that currently exist (can't disclose for privacy reasons). I am trying to create a Login Page, everything is set up to start a request using the in build "fetch(url)" command.
type Props = {};
export default class App extends Component<Props> {
constructor (Props) {
super(Props);
this.state={
username:'',
password:'',
Response:''
}
// bindings to state
this.Login = this.Login.bind(this); // you need this to be able to access state from login
this.HttpRequest = this.HttpRequest.bind(this);
this.ValidateResponse = this.ValidateResponse.bind(this);
}
Login(){
requestURL = sURL + "usr=" + this.state.username + "&" + "pwd=" + this.state.password;
var response = this.HttpRequest(requestURL);
this.setState({Response: "Response: " + JSON.stringify(response)});
}
HttpRequest(url){
return fetch(url)
.catch((error) => {
this.setState({Response: "Error: " + error});
});
}
ValidateResponse(response){
this.setState({Response: "Validating Login...\n" + response});
}
render() {
return (
// The Container for the Activity
<View style={styles.container}>
{/* The Image of The MiBase Logo */}
<View style={styles.MiBaseLogo}>
<Image resizeMode="contain" style={styles.MiBaseLogoImage} source={require("./mibaselogo.png")}/>
</View>
{/* The Text Input for the username and password*/}
<TextInput style={styles.Username} placeholder="Username" placeholderTextColor="rgb(200,200,200)"
onChangeText={(username) => {this.setState({username})}}/>
<TextInput style={styles.Password} placeholder="Password" placeholderTextColor="rgb(200,200,200)"
onChangeText={(password) => {this.setState({password})}} secureTextEntry={true}/>
{/* The Button to Command the Login Functionality */}
<TouchableOpacity style={styles.LoginButton} onPress={this.Login}>
<Text style={styles.LoginButtonText}>Login</Text>
</TouchableOpacity>
{/* The Text To Output Success or Report Failure */}
<View style={styles.TextOutput}>
<Text style={styles.TextOutputText}>{this.state.Response}</Text>
</View>
</View>
);
}
}
This is the code for my Page/Activity. I am new at this so i'm not sure if this is typically how it is done, but in order to send a request a global variable "sURL" (Assigned the name of the server) has the varaibles (usr & pwd) appended to it and sent off using fetch. when i json.stringify the response and return it to my debugging test the response is thus
Image of Page
The response when using a Http Get Request (through chrome) is
{"member": {"username":"","password":"","key":"b54d42c276a76283013589a7c285eebf","status":"No"}}
Can anyone explain this or work out what i did wrong?

Not sure why you are getting that error, I just made a form yesterday using https://github.com/gcanti/tcomb-form-native and it was very easy and worked straight away.
I get the impression though that your problem lies with your fetch, do you have access to the api backend? Also are you sending passwords in the url???
What kind of response are you expecting? When creating a login page you should really only need to know if the server accepted the login or not
EDIT:
Here is an example of my login fetch posting the login details to my API as a POST request:
onLoginPress = () => {
const value = this._form.getValue();
if(value != null){
this.setState({
fetching: true
})
var AdminLoginBindingModel = {
AdminID: 0,
AdminName: value.Username,
AdminPassword: value.Password,
}
fetch(YOUR API END POINT',
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(AdminLoginBindingModel)
})
.then((res) => res.json())
.then((json) => {
console.log(json);
this.setState({
isLoggedIn: true
})
})
.catch((error) => {
this.setState({
error: 'Something went wrong!' + error,
isLoggedIn: false,
fetching: false
})
})
}
}
Thats how I would do it but you are sending you login details as a part of the url and from your code it looks fine.
EDIT 2:
constructor(props){super(props);
this.state = {
API_Response_Status: false,
JSON_Response: {}
}
}
Then:
fetch(YOUR API END POINT',
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(AdminLoginBindingModel)
})
.then((res) => res.json())
.then((json) => {
console.log(json);
this.setState({
API_Response_Status: true,
JSON_Response: json
})
console.log(this.state.JSON_Response);
console.log(this.state.API_Response_Status);
})
.catch((error) => {
this.setState({
error: 'Something went wrong!' + error,
API_Response_Status: false,
fetching: false
})
})
}

Related

React Native Await Async does not return value before alerting user and setting state

I am using Axios to make HTTPS calls to the twitter API and return tokens and tweets:
TwitterScreen.js:
export default class TwitterLogin extends React.Component {
async componentDidMount(){
await init("<CUSTOMER KEY>", "<CUSTOMER SECRET KEY>");
this.twitter = await getToken();
alert(this.twitter);
}
render() {
return(
<View style= {styles.container}>
<Button
title="Twitter Login Button" onPress={this.twitter)}
/>
</View>
)
}
}
AxiosUtility.js:
export function init(cuskey, seckey){
axios.defaults.baseURL = 'https://api.twitter.com';
//TODO: RFC 1738 this.
axios.defaults.headers.common['Authorization'] = 'Basic ' + btoa(cuskey + ':' + seckey);
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
axios.defaults.headers.post['Accept-Encoding'] = 'gzip';
}
export function getToken(){
axios.post('/oauth2/token', 'grant_type=client_credentials', {
'User-Agent' : 'whereabouts dev',
Accept: '*/*',
})
.then((response) => {
console.log(response.data);
return (response.data);
})
.catch((error) =>{
console.log(error)
}
)
}
When console.log(response.data) runs, it returns a successful message. But it runs after an alert message is sent to the app, meaning that the alert message says "Undefined". I followed the documentation to no avail.
I also get a warning saying, "await has no effect on the type of this expression".
How do I properly utilize await and async so the alert happens after twitter is called?
getToken must return the promise i think.
export function getToken(){
//do not return void but promise with return
return axios.post('/oauth2/token', 'grant_type=client_credentials', {
'User-Agent' : 'whereabouts dev',
Accept: '*/*',
}).then((response) => {
console.log(response.data);
return (response.data);
})
.catch((error) =>{
console.log(error)
}
)
}
I noticed this recently. await doesn't work on componentDidMount().
suggestion : do your await inside some other function and that should work.

Using then() on a promise returned by fetch returns undefined in React

I'm following this tutorial: https://github.com/callicoder/spring-security-react-ant-design-polls-app
I already have a working backend that generates the JWT, and also the API returns the current user's details in http://localhost:8080/api/user/me with the GET method. All good on the back (tested with Postman).
But I have a problem when I try to load the current user from the API to the state of my App component. The idea is to create a route to the Login component and pass it a reference to the handleLogin method, which executes getCurrentUser() and redirects to the main page.
All of this is done via imports of a file called APIUtils that has methods to interact with the API. In particular, it has a generic request() method, that returns a promise using fetch, and receives the request's parameters. The problem is I can't get the response of the promise returned by the APIUtils/request() method. It says it's undefined.
App.js
//imports
class App extends Component {
state = {
currentUser: null
}
loadCurrentUser = () => {
// getCurrentUser is imported from APIUtils/index.js
getCurrentUser()
.then(response => {
this.setState({
currentUser: response
});
})
.catch(error => {
console.log(error)
});
}
handleLogin = () => {
this.loadCurrentUser();
this.props.history.push("/");
}
componentDidMount() {
this.loadCurrentUser();
}
render () {
return (
<Switch>
<Route exact path='/' component={Landing} />
<Route path="/login"
render={
(props) => <Login onLogin={this.handleLogin} {...props} />
}/>
</Route>
</Switch>
);
}
}
export default withRouter(App);
APIUtils/index.js
const request = (options) => {
const headers = new Headers({
'Content-Type': 'application/json',
})
if(localStorage.getItem(ACCESS_TOKEN)) {
headers.append('Authorization', 'Bearer ' + localStorage.getItem(ACCESS_TOKEN))
}
const defaults = { headers: headers };
options = Object.assign({}, defaults, options);
return fetch(options.url, options)
.then(response => {
response.json().then(json => {
if(!response.ok) {
return Promise.reject(json);
}
return json;
})}
);
}
// expects loginRequest = { email: 'something', password: 'something' }
export const login = (loginRequest) => {
return request({
url: API_BASE_URL + "/auth/signin",
method: 'POST',
body: JSON.stringify(loginRequest)
});
}
export const getCurrentUser = () => {
if(!localStorage.getItem(ACCESS_TOKEN)) {
return Promise.reject("No access token set.");
}
return request({
url: API_BASE_URL + "/user/me",
method: 'GET'
});
}
Login.js
class Login extends Component {
state = {
email: '',
password: ''
}
handleChange = (event) => {
this.setState({
[event.target.id]: event.target.value
});
}
handleSubmit = (event) => {
event.preventDefault();
const loginRequest = Object.assign({}, this.state);
login(loginRequest)
.then(response => {
localStorage.setItem(ACCESS_TOKEN, response.accessToken);
this.props.onLogin();
}).catch(error => {
if(error.status === 401) {
console.log('Your Username or Password is incorrect. Please try again!');
} else {
console.log('Sorry! Something went wrong. Please try again!');
}
});
}
render () {
return (
<React.Fragment>
/*
* form using onSubmit={this.handleSubmit}
* inputs using value={this.state.email} and onChange={this.handleChange}
* button of type="submit"
*/
</React.Fragment>
);
}
}
export default Login;
With this, after I log in and I load the landing page, via console I checked and I have the token in the local storage, also the request() method in APIUtils returns a response with URL: http://localhost:8080/api/user/me, and returns the json promise that's in the code, which is something like this:
{
"id": 23,
"name": "john",
"email": "new#mail.com"
}
But when I try to access the response from getCurrentUser() in App.js using then(), it response is undefined, so I can't set it to the state.
You are not returning the result of fetch():
return fetch(options.url, options)
.then(response => { // you forgot that this is also a function
return response.json().then(json => { // <--- missing return!!
if(!response.ok) {
return Promise.reject(json);
}
return json;
})}
);
I can understand why you may have missed it. It's fairly easy to miss. Which is why you should use the main feature of Promises - the reason they were invented - promise chaining:
let ok = null;
return fetch(options.url, options)
.then(response => {
ok = response.ok;
return response.json();
})
.then(json => {
if (!ok) {
return Promise.reject(json);
}
return json;
});
It's easier to spot a missing return this way because you can easily check that each then block has a return statment.

Json.stringify cannot serialize cyclic structure while taking values from state

Error is coming while hitting api
createUserProfile=async()=>{
try {
let response = await fetch(baseUrl + 'edituserprofilesave', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
hash: this.state.hash,
timestamp:this.state.timestamp,
id:this.state.id,
firstName:this.state.textFirstName,
lastName:this.state.textLastName,
picture: this.state.avatarSource.uri
}),
});
let responseJson = await response.json();
// alert("my response" + JSON.stringify(responseJson))
alert("success")
} catch (error) {
alert(error);
}
}
I know where error is coming..It is not taking textFirstName and textLastName which i am getting from here..
<FloatingLabelInput
label="First Name*"
onChange={value => {
this.setState({ textFirstName: value });
}}
style={[
styles.FloatingLabelInputStyle,
{ borderBottomColor: this.state.firstNameBorder }
]}
/>
and similarly textLast name ..I am updating state value but i don't know why it is throwing this error ..
Than you in advance

Possible unhandled promise rejection, network error when using axios

I'm trying to send JSON data using react-native, axios and Expo, but when I press "Send" on my application, I get this warning:
Possible unhandled promise rejection, Error: Network Error
My API is correctly receiving the notification (JSON) when I try to send it via POSTman, but when I try to send it using axios, I get the above warning message, so maybe react is not sending the data correctly.
export default class NotificationsInput extends React.Component {
state = {
token: '',
title: '',
body: ''
}
handleToken = event => {
this.setState({ token: event.target.value })
}
handleTitle = event => {
this.setState({ title: event.target.value })
}
handleBody = event => {
this.setState({ body: event.target.value })
}
handleSubmit = event => {
event.preventDefault();
let notification = JSON.stringify({
token: this.state.token,
title: this.state.title,
body: this.state.body
})
let headers = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
axios.post(`http://127.0.0.1:8000/send_push_message/`, notification, headers)
.then(res => {
console.log(res);
console.log(res.data)
})
.then(error => console.log(error));
}
render() {
return (
<View>
<TextInput onChange={this.handleToken}
style={{ height: 25, width: 200, borderColor: 'black', borderWidth: 1 }}
/>
<TextInput onChange={this.handleTitle}
style={{ height: 40, width: 200, borderColor: 'black', borderWidth: 1 }}
/>
<TextInput onChange={this.handleBody}
style={{ height: 40, width: 200, borderColor: 'black', borderWidth: 1 }}
/>
<Button onPress={this.handleSubmit} title="Send">Send</Button>
</View>
)
}
}
Edit :
I added the catch() function, but the error now is only Network Error in the console.
handleSubmit = event => {
event.preventDefault();
let notification = JSON.stringify({
token: this.state.token,
title: this.state.title,
body: this.state.body
})
let headers = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
axios.post(`http://127.0.0.1:8000/send_push_message/`, notification, headers)
.then(res => {
console.log(res);
console.log(res.data)
})
.catch(error => console.log(error));
}
I can see you have chained two, .then which is not correct. You need a catch block to catch network errors. Take a look below
axios.post(`http://127.0.0.1:8000/send_push_message/`, notification, headers)
.then(res => {
console.log(res);
console.log(res.data)
})
.catch(error => console.log(error));
Use catch instead of then for error handling.
.catch(error => console.log(error));
If you have cors enabled in your backend stack,
then try replacing 127.0.0.1 with 10.0.2.2
Hope this helps.

How to catch the network error while fetching the error in promise

So I have this Picker component, and for the items, I am fetching the data from the server and mapping it when the state is changed.
//api.js
var api = {
getBooks() {
var url = 'http://192.168.43.14:8080/api/books/'
var headers = new Headers();
headers.append('Accept', 'application/json');
return fetch(url, headers)
.then((res) => res.json())
.catch(function(err) {
console.log('Fetch Error :-S', err);
throw Error(err);
});
}
}
//RegisterMobile.js
import api from '../utilities/api'
export default class RegisterMobile extends Component {
constructor(props) {
super(props)
this.state = {
books: [],
book: '',
mobile: '',
displayError: false,
error: 'Please provide a valid mobile number'
}
}
componentWillMount() {
api.getBooks().then((res) => {
this.setState({
books: res
})
})
}
render() {
return(
<View>
<View style={styles.selecBook}>
<Picker selectedValue={this.state.book} onValueChange={this.changeBook}>
{this.state.books.map((book) => {return <Picker.Item value={book.name} label={book.name} key={book.id} />})}
</Picker>
</View>
{this.state.displayError ? <Text style={styles.error}>{this.state.error}</Text> : null}
</View>
)
}
}
This is working fine. I get the list of items and when I click on the Picker, I can select the items. What I want to do is, if there was any error while fetching the data (eg. server is down), I would like to get that error and display it as error (which would be just changing the state of error and displayError). But I don't know how to get the error if there was one to set it in the state of the error.
Don't catch the error inside the api. Do it where you want to use the result of the async operation. Something like this...
//api.js
var api = {
getBooks() {
var url = 'http://192.168.43.14:8080/api/books/'
var headers = new Headers();
headers.append('Accept', 'application/json');
return fetch(url, headers)
.then((res) => res.json());
}
}
//RegisterMobile.js
import api from '../utilities/api'
export default class RegisterMobile extends Component {
constructor(props) {
super(props)
this.state = {
books: [],
book: '',
mobile: '',
displayError: false,
error: 'Please provide a valid mobile number'
}
}
componentWillMount() {
api.getBooks()
.then((res) => { this.setState({books: res}) })
.catch(function(err) {
console.log('Fetch Error :-S', err);
this.setState({books: [], book: null, displayError: true, error:err});
});
}
componentWillMount() {
api.getBooks()
.then((res) => { this.setState({books: res}) })
.catch(function(err) {
if (err.message === 'Network Error') {
// This is a network error.
}
});
}

Categories

Resources