I have a react app which calls an API when the user clicks login. However, the response that react native receives is different than the intended response.
React Native code:
login() {
this.setState({isLoading: true})
return fetch(process.env.API_USER + "/signin", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
username: this.state.username,
password: this.state.password
})
}).then((response) => {
console.log(`\n\n\n\nRESPONSE---->${JSON.stringify(response)}\n\n\n\n`)
this.setState({isLoading: false})
})
.catch((error) => {
console.log((`\n\n\n\nERROR---->${error}\n\n\n\n`))
this.setState({isLoading: false})
})
}
Console response:
RESPONSE---->{"type":"default","status":401,"ok":false,"headers":{"map":{"via":"1.1 vegur","date":"Thu, 27 Sep 2018 18:10:42 GMT","server":"Cowboy","etag":"W/\"17-wIxJlIRlPQbTEtBjbmLpTqPMWNo\"","connection":"keep-alive","cache-control":"public, max-age=0","x-powered-by":"Express","content-length":"23","access-control-allow-credentials":"true","access-control-allow-origin":"*","access-control-allow-methods":"*","access-control-allow-headers":"Origin, Accept,Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers","content-type":"application/json; charset=utf-8"}},"url":"abc.com","_bodyInit":{"_data":{"size":23,"offset":0,"blobId":"f4012672-62b8-4b52-be6f-06446874981c"}},"_bodyBlob":{"_data":{"size":23,"offset":0,"blobId":"f4012672-62b8-4b52-be6f-06446874981c"}}}
expected API response:
RESPONSE---->{"message": "Auth Fail"}
// ----------OR---------- //
RESPONSE---->{"message": "Auth Successfull"}
As the previous answers have noted, the response object has a .json() function which returns a promise (which resolves to the actual data).
Also you can structure the code much better with async/await
login = async () => {
const options = {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
username: this.state.username,
password: this.state.password
}),
};
this.setState({isLoading: true});
try {
const response = await fetch(`${process.env.API_USER}/signin`, options);
const responseData = await response.json(); // This is what you're missing
this.setState({isLoading: false});
} catch (error) {
// Do something about the error
console.log((`\n\n\n\nERROR---->${error}\n\n\n\n`));
}
}
In document basic structure of fetch request defined here. from the document, you can try this one
.then((response) => response.json())
.then((resJSON) => {
console(resJSON);
this.setState({isLoading: false})
})
.catch((error) => {
console.log(error)
this.setState({isLoading: false})
})
You need to have another .then that will resolve the response and converts it into JSON:
.then(response => response.json())
.then(data => {
// now you can get your server response
console.log(data)
})
Related
currently I'm fetching data from my api to front-end. I checked and my request body is arriving to server side. But after doing things when it comes to returning the token it always returns undefined data to vue.js:
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody]User user)
{
var result = await _accountRepository.LoginAsync(user.username, user.password);
if (string.IsNullOrEmpty(result))
{
return Unauthorized(result);
}
Debug.WriteLine(result.ToString()); // this works and I can see the token
return Ok(result);
}
When it comes here:
methods: {
login() {
fetch("http://localhost:60427/api/account/login", {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
username: this.username,
password: this.password,
})
}).then(response => {
console.log(response.data); // this is always undefined
})
.catch(e => {
console.log(e);
});
},
}
Please help I can't see any errors here. I'm confused.
You need to call either Response.text() or Response.json() depending on what data you expect. These methods return a Promise that resolves to the data.
E.g. for JSON:
fetch("http://localhost:60427/api/account/login", {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
username: this.username,
password: this.password,
})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(e => console.error(e));
got the title error and can't fix it :(. I'm triying to get the data from a signup page, here is my javascript code:
const SignupComponent = () => {
const [values, setValues] = useState({
name: 'ryan',
email: 'ryan#gmail.com',
password: 'rrrrrr',
error: '',
loading: false,
message: '',
showForm: true
});
const { name, email, password, error, loading, message, showForm } = values;
const handleSubmit = e => {
e.preventDefault();
// console.table({ name, email, password, error, loading, message, showForm });
setValues({ ...values, loading: true, error: false });
const user = { name, email, password };
signup(user).then(data => {
if(data.error) {
setValues({ ...values, error: data.error, loading: false });
} else {
setValues ({ ...values, name: '', email: '', password: '', error: '', loading: false, message: data.message, showForm: false});
}
});
};
const handleChange = name => e => {
setValues({ ...values, error: false, [name]: e.target.value })
, so when i try to register in the page, its says TypeError: can't access property "error", data is undefined.
signup(user).then(data => {
> 25 | if(data.error) {
| ^
26 | setValues({ ...values, error: data.error, loading: false });
27 | } else {
Signup Function
export const signup = (user) => {
return
fetch(${API}/signup, { method: 'POST',
headers: { Accept: 'application/json',
'Content-Type': 'application/json' },
body: JSON.stringify(user) })
.then(response => { return response.json(); })
.catch(err => console.log(err));
i'm kinda nooby in programming but i already look in the internet for a solution, nothing works u.U
I guess you are not quite familiar with the concept of Asynchronous programming. Fetch is an Async function and if you want to wait for it's output you have to you use the Await keyword which also requires signup to be Async. So your code will look some what like this:
export const signup = async (user) => {
let fetchResponse = fetch(${API}/signup, { method: 'POST',
headers: { Accept: 'application/json',
'Content-Type': 'application/json' },
body: JSON.stringify(user) });
return (await fetchResponse.json())
To Learn more about Asynchronous programming, I recommend reading this article https://blog.risingstack.com/node-hero-async-programming-in-node-js/
When you called json() method in fetch response a Promise is returned since reading a stream object will happen aysnchronously. So what you is to chain another then function to get that data like this.
export const signup = user => {
return fetch(`${API}/signup`, {
method: "POST",
headers: { Accept: "application/json", "Content-Type": "application/json" },
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.then(data => {
return data;
})
.catch(err => console.log(err));
};
PS: neither you need to use async/ await since you are using Promises with .then(), nor there is any need for chaining with one more .then() inside signup() since you are already doing that in handleSubmit() where you've called signup().
Try re-writing your signup() function as below. I guess you've missed back-ticks because I've implemented the SignUp in a similar way and it works for me. Let me know if it helps:
export const signup = (user) => {
return fetch(`${API}/signup`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
PS: neither you need to use async/await since you are using Promises with .then(), nor there is any need for chaining with one more .then() inside signup() since you are already doing that in handleSubmit() where you've called signup().
I'm trying to include credentials to my requests
I'm using axios but axios don't send credentials with request.
This is how i do it with axios.
const axiosConfig = {
withCredentials: true,
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
};
axios
.get("someurl" + data, axiosConfig)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
But when i try it with fetch everything work.
fetch("someurl" + data, {
credentials: "include"
})
.then(function(response) {
return response.json();
})
.then(result => {
console.log(result);
});
how make it work with axios too?
You should see the auth parameter inside the axios config object
auth: {
username: 'janedoe',
password: 's00pers3cret'
}
see https://github.com/axios/axios
I am trying to fetch multiple requests in an order in React. There are 3 requests,
first one gathering encoded information from backend
get token from authentication server
use api with the token.
All of them must be in order. But I am having difficulties because of async fetch function. I can't reach fetch's response outside of .then() block.
To solve it, I used await / async. But it caused another problem. My 3 requests must be in a sequencial order. When I use async, order gets broken.
Here is the code.
class App extends Component {
constructor() {
super();
this.state = { code: '', encoded: '', access_token: '', refresh_token: '' };
}
getCarDetails() {
const carId = '2F3A228F6F66AEA580'
var query = 'https://api.mercedes-benz.com/experimental/connectedvehicle/v1/vehicles/'.concat(carId).concat('/doors')
fetch(query, {
method: 'GET',
headers: {
'Authorization': 'Bearer '.concat(this.state.access_token),
'accept': 'application/json'
}
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.log(err));
}
getToken() {
var post_data = {
grant_type: 'authorization_code',
code: this.state.code,
redirect_uri: 'http://localhost'
}
fetch('https://api.secure.mercedes-benz.com/oidc10/auth/oauth/v2/token', {
method: 'POST',
headers: new Headers({
'Authorization': 'Basic '.concat(this.state.encoded),
'Content-Type': 'application/x-www-form-urlencoded'
}),
body: queryString.stringify(post_data)
})
.then(res => res.json())
.then(data => this.setState({ access_token: data.access_token, refresh_token: data.refresh_token }))
.catch(err => console.log(err));
}
getEncodedClientIdAndClientSecret() {
if (this.state.code != null) {
fetch('http://localhost:8000/encodeClientIdAndSecret', {
method: 'POST'
})
.then(res => res.json())
.then(data => this.setState({ encoded: data.encoded }))
.catch(err => console.log(err));
}
}
componentDidMount() {
const values = queryString.parse(this.props.location.search)
this.setState({ code: values.code })
console.log(this.state)
this.getEncodedClientIdAndClientSecret();
console.log(this.state) //this state is empty
//this.getToken();
//this.getCarDetails();
}
AWAIT / ASYNC
async getEncodedClientIdAndClientSecret() {
if (this.state.code != null) {
const response = await fetch('http://localhost:8000/encodeClientIdAndSecret', {
method: 'POST'
})
const data = await response.json();
console.log(data)
}
}
If I put await / async, I am having sequence problem between 3 requests.
in order to use async await on methods like
await getEncodedClientIdAndClientSecret();
await getToken();
you need to first return a promise from those functions like:
getToken() {
var post_data = {
grant_type: 'authorization_code',
code: this.state.code,
redirect_uri: 'http://localhost'
}
return fetch('https://api.secure.mercedes-benz.com/oidc10/auth/oauth/v2/token', {
method: 'POST',
headers: new Headers({
'Authorization': 'Basic '.concat(this.state.encoded),
'Content-Type': 'application/x-www-form-urlencoded'
}),
body: queryString.stringify(post_data)
})
.then(res => res.json())
.then(data => this.setState({ access_token: data.access_token, refresh_token: data.refresh_token }))
.catch(err => console.log(err));
}
so it can wait for the promise to finish, othewise they will run in parallel and finish in random order.
I am using react native to create an application to act as a website that currently exists (with a user interface that works on a phone). i am using the "fetch" method to send a Http POST request to get information from a web server. The web server sends a response but it doesn't include the response message:
I apologies that is an image but the debugger is not working for me.
The code used to send the request:
HttpRequest = (RequestURL, callback) => {
var AdminLoginBindingModel = {
usr: this.state.username,
pwd: this.state.password,
}
fetch(RequestURL,
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(AdminLoginBindingModel)
})
.then((res) => {
callback(res);
})
.catch((error) => {
this.setState({Response: "Error: " + error});
})
}
The callback function in the parameters is just a function to change the state variable to display the information on the screen
ValidateResponse(response){
this.setState({Response: "Result: " + JSON.stringify(response),
displayMessage: "Success"});
console.log(JSON.stringify(response));
}
The Request being sent is "https://mibase-test.mibase.com.au/members/api/startSession.php?usr=&pwd="
The server responds with a json object regardless of a correct login or not
Edit:
Changing the response to
.then((res) => {
callback(res.json());
})
Result:
To get object from fetch response, you have to call res.json like following:
fetch(RequestURL, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(AdminLoginBindingModel)
})
.then(res => res.json()) // HERE
.then(obj => callback(obj))
But it occurs an error because response body itself is invalid json format. It contains some HTML tags:
{"member": {"username":"","password":"","key":"***","status":"No"}}<br><br>Username: <br>Key: ***
Please check the inplementation of server.
EDIT: full code here
const fetch = require("node-fetch")
HttpRequest = (RequestURL, callback) => {
const AdminLoginBindingModel = { usr: "foo", pwd: "bar" }
fetch(RequestURL, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(AdminLoginBindingModel)
})
.then(res => res.json())
.then(obj => callback(obj))
.catch(error => console.log(error))
}
const ValidateResponse = response => console.log(JSON.stringify(response))
URL = 'https://mibase-test.mibase.com.au/members/api/startSession.php?usr=&pwd='
HttpRequest(URL, ValidateResponse)
response doesn't contain received data directly. It provides interface methods to retrieve it. For example use response.json() to parse response text as JSON. It will return promise that resolves to the parsed object. You won't need to call JSON.parse on it:
fetch(RequestURL,
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(AdminLoginBindingModel)
})
.then((res) => {
return res.json();
}).then((obj) => {
console.log(obj);
});
Check https://developer.mozilla.org/en-US/docs/Web/API/Response and https://facebook.github.io/react-native/docs/network.html for more information.