Fetch().then() does not return data - reactjs

I am having some trouble in getting fetch return data from my cloud function, I am only trying to write data into google spreadsheet with cloud function for now. Below is my current code so far.
I have a button with onClick={this.AddRecord} which will then call the cloud function
AddRecord = async () => {
await fetch(url, {
method: 'POST',
body: JSON.stringify({
date: this.getDate(),
name: this.state.name,
number: '\'' + this.state.number
})
})
.then((response) => {return response.json()})
.then((data) => {
alert(data) // this never gets executed
this.setState({message:data})
})
.catch((err) => {
this.setState({message: err})
});
}
and this is my cloud function POST handler:
case 'POST':
/* parse the string body into a usable JS object */
const data = JSON.parse(event.body);
const addedRow = await sheet.addRow(data);
return {
statusCode : 200,
body: JSON.stringify({
message : 'Posted successfully.',
rowNumber: addedRow._rowNumber - 1 // minus the header row
})
};
Appreciate it if anyone could point me in the right direction, as I have spent a lot of time trying to debug this but with no avail.
some of the resource that I have read so far:
fetch() call not returning any data
https://www.smashingmagazine.com/2020/06/rest-api-react-fetch-axios/
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
Edit:
I have tried to call the cloud function via POSTMAN and successfully gotten a status 200 response with message.
So I can safely assume that the issue is not with the cloud function but the fetch function, but I am still clueless on which part of the code went wrong as they seem pretty much the same as other code example that I see online. I will only get TypeError: Failed to fetch when I switch back to POST from my react app.

Change your function to this:
AddRecord = async () => {
await fetch(url, {
method: 'POST',
headers: { 'Content-Type':'application/json' }, // here is the change
body: JSON.stringify({
date: this.getDate(),
name: this.state.name,
number: '\'' + this.state.number
})
})
.then((response) => response.json())
.then((data) => {
alert(data)
this.setState({message:data})
})
.catch((err) => {
this.setState({message: err})
});
}

Related

Fetch POST request console.log not working correctly

While I can post data to my server, and the server console.log works, I cannot for the life figure out why the client side console.log isn't working. What am I missing here?
The Error: SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
Status: 200 OK
Request: {"hotSauceId":32,"presentation":5,"viscosityId":3,"spiciness":10,"Flavor_Notes":["Constituent Peppers"],"overall_rating":5,"lovedit":true,"taster_notes":"test"}
Looks json to me?
Submit Handler:
const handleSubmit = (e) => {
e.preventDefault();
fetch('http://jyh:3000', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({
"hotSauceId": sauce,
"presentation": presentation,
"viscosityId": viscosity,
"spiciness": spiciness,
"Flavor_Notes": flavor,
"overall_rating": overall,
"lovedit": loved,
"taster_notes": notes
}),
}).then(res => {
return res.json();
}).then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
};
Server Code:
app.post('/', async (req, res) => {
await Jyh.create({ // .create is a Sequelize method
hotSauceId: req.body.hotSauceId,
presentation: req.body.presentation,
viscosityId: req.body.viscosityId,
spiciness: req.body.spiciness,
Flavor_Notes: req.body.Flavor_Notes,
overall_rating: req.body.overall_rating,
lovedit: req.body.lovedit,
taster_notes: req.body.taster_notes
}).then(() => {
console.log('req.body: ', req.body);
}).catch((err) => {
console.log(err);
});
});
It should console.log the response in the client console, but instead I receive an error.
Github repository for the client and server app.

ReactJS is throwing an error when catching a response from .NET API

I am connecting my ReactJS web app to my .NET Api and I am receiving an error whenever REACTJS is receiving the response from the API.
Here is what the error is saying
The api is returning a STRING which is the JWT token. Here is the code for that particular task:
public IActionResult Login([FromBody] UserLogin userLogin)
{
var user = Authenticate(userLogin);
if (user != null)
{
var token = Generate(user);
return Ok(token);
}
else
{
return NotFound("User not found");
}
}
and here is the fetch method in REACTJS that is responsible for this task:
function getJWTToken(event) {
event.preventDefault();
const userCredentials = {
email: user_email,
password: user_password,
};
const url = Constants.API_URL_LOGIN;
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(userCredentials),
})
.then((response) => response.json())
.then((data) => {
console.log("Success:", data);
})
.catch((error) => {
console.error("Error:", error);
});
}
I spent two hours already but I cannot figure out what to do in here since this is my first project using react and .net. Thank you for your help.
Since you are not receiving json but plain text, use response.text() to read the response
I solved my propblem now. Thank you to Stutje, he gave me the idea. Instead of using response.json() , response.text() worked.

update the state of my component with the response data after Post request with axios

I'm trying to update the state of my component with the response data after Post request with axios but it returns an empty array when I log out the updated state with console.log(), but shows the response.data information received with .then in axois in the broswer console. Please help me out
Code starts here
const [offers, setOffers] = useState({});//THIS IS THE STATE
const search async (e) => {
e.preventDefault();
const options = {
url: "localhost:8080/api/search",
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
data,
};
axios(options)
.then((response) => {
console.log(response.data.data);// THIS RETURNS OBJECT DATA GOTTEN FROM THE SERVER AFTER POST REQUEST
setOffers(response.data.data); //IT DOES NOT UPDATE WITH RESPONSE DATA
console.log(offers); = IT RETURNS AND EMPTY ARRAY
})
.catch(function (error) {
if (error.response) {
setValerr(error.response.data.errors);
console.log(error.response);
}
});
};
thanks in advance
In react, setState is asynchronous, so when you call "setOffers" it is an asyncronous action.
Therefore when you call console.log, offers might not be updated yet.
You can read more about it here:
https://reactjs.org/docs/faq-state.html#when-is-setstate-asynchronous
To listen to the value of "offers" you might need to use useEffect
An example
const [offers, setOffers] = useState({}) //THIS IS THE STATE
const search = async (e) => {
e.preventDefault()
const options = {
url: 'localhost:8080/api/search',
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json;charset=UTF-8',
},
data,
}
axios(options)
.then((response) => {
console.log(response.data.data) // THIS RETURNS OBJECT DATA GOTTEN FROM THE SERVER AFTER POST REQUEST
setOffers(response.data.data) //IT DOES NOT UPDATE WITH RESPONSE DATA
console.log(offers)
})
.catch(function (error) {
if (error.response) {
setValerr(error.response.data.errors)
console.log(error.response)
}
})
}
useEffect(() => {
// This should log offers to the console if it has been set
if(offers) {
console.log(offers)
}
}, [offers])

How do i set the state from one API call and use the data for URL in next API call?

I need the data from API call 1 to add to the URL of API call 2. The data from API 2 will go into the URL for API 3. I am setting the state on each Axios request and it is not working. Returning undefined
componentDidMount() {
// Get the IP adress of user
axios
.get('https://api.ipify.org?format=json')
.then(res => {
this.setState({
ip: res.data.ip
});
console.log(`IP : ${this.state.ip}`);
})
.catch(err => console.log(err));
// GET the coordinates of a location based on IP adress
axios
.get(
'https://geo.ipify.org/api/v1?apiKey=YOUR_API_KEY&ipAddress=24.8.227.87'
)
.then(res => {
this.setState({
latitude: res.data.location.lat,
longitude: res.data.location.lng
});
console.log(
`Latitude: ${this.state.latitude}. Longitude: ${this.state.longitude}`
);
})
.catch(err => console.log(err));
// Make the API call on page load
axios({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/geocode?lat=39.6924553&lon=-105.0256318`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
'user-key': 'USER_KEY'
}
})
.then(res => {
const restaurantsNearMe = res.data.nearby_restaurants;
this.setState({
restaurants: restaurantsNearMe
});
// Pick out a random retaurant from what the API returns
var randomRestaurant =
restaurantsNearMe[
Math.floor(Math.random() * restaurantsNearMe.length)
];
// Select only the data that you want
var finalResult = {
name: randomRestaurant.restaurant.name,
id: randomRestaurant.restaurant.id,
rating: randomRestaurant.restaurant.user_rating.aggregate_rating,
ratingColor: randomRestaurant.restaurant.user_rating.rating_color,
address: randomRestaurant.restaurant.location.address,
delivery: randomRestaurant.restaurant.is_delivering_now,
typeOfFood: randomRestaurant.restaurant.cuisines
};
this.setState({
restaurant: finalResult
});
console.log(this.state.restaurant);
})
.catch(err => console.log(err));
}
You need a callback in setState, and in that callback you need to call your second API and so on. Check this.
This is what you want,
axios
.get('https://api.ipify.org?format=json')
.then(res => {
this.setState({
ip: res.data.ip
}, () => {
// GET the coordinates of a location based on IP adress
axios
.get(
'https://geo.ipify.org/api/v1?apiKey=YOUR_API_KEY&ipAddress=24.8.227.87'
)
.then(res => {
this.setState({
latitude: res.data.location.lat,
longitude: res.data.location.lng
}, () => {
// Make the API call on page load
axios({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/geocode?lat=39.6924553&lon=-105.0256318`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
'user-key': 'USER_KEY'
}
})
.then(res => {
const restaurantsNearMe = res.data.nearby_restaurants;
this.setState({
restaurants: restaurantsNearMe
});
// Pick out a random retaurant from what the API returns
var randomRestaurant =
restaurantsNearMe[
Math.floor(Math.random() * restaurantsNearMe.length)
];
// Select only the data that you want
var finalResult = {
name: randomRestaurant.restaurant.name,
id: randomRestaurant.restaurant.id,
rating: randomRestaurant.restaurant.user_rating.aggregate_rating,
ratingColor: randomRestaurant.restaurant.user_rating.rating_color,
address: randomRestaurant.restaurant.location.address,
delivery: randomRestaurant.restaurant.is_delivering_now,
typeOfFood: randomRestaurant.restaurant.cuisines
};
this.setState({
restaurant: finalResult
});
console.log(this.state.restaurant);
})
.catch(err => console.log(err));
});
console.log(
`Latitude: ${this.state.latitude}. Longitude: ${this.state.longitude}`
);
})
.catch(err => console.log(err));
});
console.log(`IP : ${this.state.ip}`);
})
.catch(err => console.log(err));
one thing to keep in mind, this.setState is not synchronous. React batches multiple set state calls to improve render performance. That's why you might be seeing undefined in the console.log.
setState method takes a callback as second parameter.
this.setState(newState, callbalck)
so try to console log in the callback and give it a try.
I dont know how do you call API's but, try something like this:
In componentDidMount you can do this:
async componentDidMount(){
const resApiOne = await callFirstApi();
this.setState({resApiOne});
const resApiTwo = await callSecondApi(resApiOne);
this.setState({resApiTwo});
}

Fetch request always returns network error

I almost finished creating React Native application, few days ago register action has stopped working.. I'm sending fetch request and it always returns network error altough there is 400 response and message that user exists, it stops there..
I'm destructuring the response and displays api response message instead of fetch network error but now it doesn't work. I'm doing the same for the login action and it works.
Could it be something with multipart/form-data ?
export const register = data => dispatch => {
dispatch(createUser());
const d = new FormData();
d.append("name", data.name);
d.append("email", data.email);
d.append("password", data.password);
d.append("avatar", data.avatar);
fetch(API_URL + "/register", {
method: "POST",
headers: {
"content-type": "multipart/form-data"
},
body:d
})
.then(response => response.json().then(user => ({ user, response })))
.then(({ user, response }) => {
if (!response.ok) {
console.log(response, user)
} else {
console.log(response, user)
}
})
.catch(err => {
throw err;
});
};
The api route works in Postman..
In this case, your using fetch which is Promise based incorrectly,
Try,
fetch(API_URL + "/register", {
method: "POST",
headers: { "content-type": "multipart/form-data" },
body:d
})
.then(response => {
console.log(response, response.json().user)
})
.catch(err => {
console.log(err)
});
Check the logs and see if it shows proper network response and debug from there.

Resources