I am using node-fetch to fetch data from REST API.
Here is my code:
this.getUserList = async (req, res) => {
const fetch = require('node-fetch');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
let params = {
"list_info": {
"row_count": 100
}
}
fetch('https://server/api/v3/users?input_data=' + JSON.stringify(params), {
headers:{
"TECHNICIAN_KEY": "sdfdsfsdfsd4343323242324",
'Content-Type': 'application/json',
},
"method":"GET"
})
.then(res => res.json())
.then(json => res.send(json))
.catch(err => console.log(err));
}
It works fine.
However, if I change the following statement:
let params = {"list_info":{"row_count": 100}}
To
let params = {"list_info":{"row_count": 100}, "fields_required": ["id"]}
It prompts the following error message:
FetchError: invalid json response body at https://server/api/v3/users?input_data=%7B%22list_info%22:%7B%22row_count%22:100%7D,%22fields_required%22:[%22id%22]%7D reason: Unexpected end of JSON input`
The problem is that you are not URL-encoding your query string. This can be easily accomplished using URLSearchParams.
Also, GET requests do not have any request body so do not need a content-type header. GET is also the default method for fetch()
const params = new URLSearchParams({
input_data: JSON.stringify({
list_info: {
row_count: 100
},
fields_required: ["id"]
})
})
try {
// 👇 note the ` quotes
const response = await fetch(`https://server/api/v3/users?${params}`, {
headers: {
TECHNICIAN_KEY: "sdfdsfsdfsd4343323242324",
}
})
if (!response.ok) {
throw new Error(`${response.status}: ${await response.text()}`)
}
res.json(await response.json())
} catch (err) {
console.error(err)
res.status(500).send(err)
}
Related
I have tried so many thing but my react app is not recieving jsonData variable or res as a return from the node app. The app is working and printing to console on the node side but I can't get it to print onto the react side.
const submitForm = async (event) => {
event.preventDefault(); // Prevent default submission
const data2 = document.getElementById("miles").value;
const data =
"passenger_vehicle-vehicle_type_" +
carType +
"-fuel_source_" +
vehicleType +
"-engine_size_na-vehicle_age_na-vehicle_weight_na";
axios
.post(`http://localhost:8000/api/vehicle/`, { data, data2 })
.then((res) => {
const returnText = res.json();
console.log(returnText);
return res.json();
})
.then((jsonData) => {
console.log(jsonData);
return;
})
.catch((error) => {
console.log("got errr while posting data", error);
});
};
I edited out the api and api key.
var fetch = require('node-fetch');
exports.vehicle = (req, res) =>{
let status;
const { data, data2 } = res.body;
const values = {
"emission_factor": data,
"parameters": {
"distance": parseInt(data2),
"distance_unit": "mi",
},
};
fetch('https://AAAAAAAAAAAAAAAA', {
method: 'POST',
headers: {
'Authorization': 'Bearer MYAPIKEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
})
.then((res) => {
status = res.status;
return res.json()
})
.then((jsonData) => {
console.log(jsonData);
console.log(status);
return jsonData
})
.catch((err) => {
// handle error
console.error(err);
});
res.send(req.body);
}
Working code thanks for the help:
const submitForm = async (event) => {
event.preventDefault(); // Prevent default submission
const data2 = document.getElementById("miles").value;
const data =
"passenger_vehicle-vehicle_type_" +
carType +
"-fuel_source_" +
vehicleType +
"-engine_size_na-vehicle_age_na-vehicle_weight_na";
axios
.post(`http://localhost:8000/api/vehicle/`, { data, data2 })
.then((res) => {
console.log(res.data);
return;
})
.catch((error) => {
console.log("got err while posting data", error);
});
};
Node solution in comments.
The functions inside your then() statements need to return data e.g. then((res) => {return res.json()})
You have two problems here...
Client-side, you seem to be mixing up an Axios response with a fetch() Response. You want res.data, not res.json(). Since you've tagged this with reactjs, here is where you would set the data to a state value, eg
axios.post(...).then(res => {
setSomeState(res.data)
})
Server-side, you aren't waiting for your fetch request to complete. I'd recommend using an async function
exports.vehicle = async (req, res) => {
try {
const { data, data2 } = req.body
const values = {
"emission_factor": data,
"parameters": {
"distance": parseInt(data2),
"distance_unit": "mi",
},
}
// don't mix up the Express "res" with the fetch "response"
const response = await fetch('https://AAAAAAAAAAAAAAAA', {
method: 'POST',
headers: {
'Authorization': 'Bearer MYAPIKEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
})
if (!response.ok) {
throw new Error(`${response.status}: ${await response.text()}`)
}
res.json(await response.json()) // respond with the data
} catch (err) {
console.error(err)
res.status(500).send(err)
}
}
I am trying to make my server a middleman so that the frontend queries the server with a searchedValue, the server queries the API with the searchedValue, and the server returns the API response to the frontend.
Currently, the server is querying the API correctly. Here is the code and responses:
Query: http://localhost:3000/optionsAPI/AAPL
Code [server.js]:
app.get("/optionsAPI/:ticker", (req, res) => {
var tempJSON = [];
const searchString = `${req.params.ticker}`;
const url = `API URL HERE, HIDING FOR SECURITY`;
fetch(url, { headers: { Accept: 'application/json' } })
.then(res => res.json()
.then((json) => {
tempJSON = json;
console.log(tempJSON);
}))
.catch(err => console.error(err)); // eslint-disable-line
res.send({ message: tempJSON });
});
Here is the code in the component:
Code [Component.js]:
useEffect(() => {
const fetchData = () => {
const url = `/optionsAPI/${searchedValue}`;
fetch(url, { headers: { Accept: 'application/json' } })
.then(res => res.json()
.then((json) => {
setOptions(json.option_activity || []);
}))
.catch(err => console.error(err)); // eslint-disable-line
};
debounce(fetchData());
}, [searchedValue]);
The console log is perfect! It logs tempJSON as I would expect to see it, but the res.send message is simply {"message":[]}. Therefore, the response my frontend gets is an empty []. This doesn't; make sense - the console is logging the response, so why is the frontend receiving a blank []?
Thanks in advance.
In your code you are calling an api which returns a promise, so to handle the data returned by the promise you should add your code inside .then() function, meaning you have to wait for the promise to be resolved before accessing the data and sending it to the client
app.get("/optionsAPI/:ticker", (req, res) => {
var tempJSON = [];
const searchString = `${req.params.ticker}`;
const url = `API URL HERE, HIDING FOR SECURITY`;
fetch(url, { headers: { Accept: 'application/json' } })
.then(res => res.json()
.then((json) => {
tempJSON = json;
console.log(tempJSON);
// the response should be sent from here
res.send({ message: tempJSON });
}))
.catch(err => {
console.error(err);
// you also need to send a response when catching erros
res.status(400).send({ err });
});
});
you can use async / await to make your code much cleaner
app.get("/optionsAPI/:ticker", async (req, res) => {
var tempJSON = [];
const searchString = `${req.params.ticker}`;
const url = `API URL HERE, HIDING FOR SECURITY`;
try {
const result = await fetch(url, { headers: { Accept: 'application/json' } })
const json = await result.json()
tempJSON = json;
console.log(tempJSON);
res.send({ message: tempJSON });
} catch (error) {
console.error(error);
res.status(400).send({ error });
}
});
Here is my React code for the form submission:
const handleSubmit = (e) => {
e.preventDefault();
console.log('item:', item);
Axios.post('http://<MY_SERVER>/item/add', {name:item})
.then(response => console.log(response))
.catch(err => console.log(err));
};
and this is the code in my Node API:
// Add a new Item
app.post('/item/add', (req, res) => {
const newItem = new Item({
name: req.body.name
});
newItem.save()
.then(item => {
res.json({msg: 'success'});
})
.catch(err => console.log(err));
});
When I run the handleSubmit nothing happens. I only get the console.logs... Also, here is the error from my server
'ValidationError: item validation failed: name: Path' `name` is required
So it is clear that the data sent over to the api is never received. I've tried changing it up in many ways I have came across online but no luck.
I have attached both ways to post data i.e. Form URL Encoded and JSON. For sending Form Url Encoded data we need an additional Library querystring.
You can install it using npm install query-string
Here is the code for both the requests. You don't need query-string if you are using content type application/json.
Here you go
var axios = require('axios');
const qs = require('querystring');
function sendFormUrlEncodedData() {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
const payload = {
name: 'morpheus',
job: 'leader'
};
//Send data with form url using querystring node package for it.
axios
.post('https://reqres.in/api/users', qs.stringify(payload), {
headers: headers
})
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
function sendJSONData() {
const headers = {
'Content-Type': 'application/json'
};
const payload = {
name: 'morpheus',
job: 'leader'
};
//Send data with JSON, so stringifying it.
axios
.post('https://reqres.in/api/users', JSON.stringify(payload), {
headers: headers
})
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
sendFormUrlEncodedData();
sendJSONData();
First of all check whether your backend code is working or not by using postman. I think you are getting validation error because of the error of your backend code. And also check whether that you are implemented the name attribute correctly with its data type.
After that update, the react code as below.
import axios from 'axios';
constructor() {
this.item = {
name: ''
}
}
handleSubmit(event) {
console.log('item:', this.item.name);
event.preventDefault();
axios.post('http://<MY_SERVER>/item/add', this.item)
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});
}
I have the following piece of code which is working perfect. However, my task is to replace fetch with axios. can you please guide, what would be the correct replacement of code in axios?
const create = async (credentials, software) => {
return await fetch('/api/software/create', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + credentials.t
},
credentials: 'include',
body: JSON.stringify(software)
})
.then((response) => {
return response.json()
}).catch((err) => console.log(err))
}
create({ t: jwt.token }, data)
.then((data) => {
if (data.error) {
this.setState({ error: data.error })
} else {
this.props.dispatch(initSoftware()); //if successful get the list of softwares in redux store
}
})
The data variable is an object which hold the req.body equivalent...
The above code is written in react and the create() is called within onSubmit eventhandler.
I am sure if I use axios the create() would be eliminated.. but how? Please guide..
It shouldn't be too different than what you currently have but something like this...
const create = async (credentials, software) => {
return await axios({
url: '/api/software/create'
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + credentials.t
},
withCredentials: true,
data: JSON.stringify(software)
})
.then((response) => {
return response.data;
}).catch((err) => console.log(err))
}
create({ t: jwt.token }, data)
.then((data) => {
if (data.error) {
this.setState({ error: data.error })
} else {
this.props.dispatch(initSoftware()); //if successful get the list of softwares in redux store
}
})
Note that the data you would be looking for should be in a property called data.
For more, check out the API references here.
2021 answer: just in case you land here looking for how to make GET and POST Fetch api requests using async/await or promises as compared to axios.
I'm using jsonplaceholder fake API to demonstrate:
Fetch api GET request using async/await:
const asyncGetCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncGetCall()
Fetch api POST request using async/await:
const asyncPostCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
});
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncPostCall()
GET request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
POST request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
})
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
GET request using Axios:
const axiosGetCall = async () => {
try {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosGetCall()
POST request using Axios:
const axiosPostCall = async () => {
try {
const { data } = await axios.post('https://jsonplaceholder.typicode.com/posts', {
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosPostCall()
I am making a demo react-redux app for the basic understanding of redux and its server is made on nodeJS. I have made a simple form which gets submitted and the server response is res.send('FORM SAVED'). In front-end, I make the post request but is not able to see the response that returns, be it the success response.
My server controller that responds when form details are saved.
export const postData = (req, res) => {
let p = new PostData();
p.name = req.body.name;
p.emp_id = req.body.emp_id;
p.age = req.body.age;
p.dept = req.body.dept;
p.phone = req.body.phone;
p.gender = req.body.gender;
p.save(((err) => {
if (err){res.send(`Error in uploading: ${err}`);}
else {res.send('Form saved');}
}));
}
This is my action:-
export const createPost = postData => dispatch => {
fetch(`${Config.address}/post`, {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
})
.then((post) => {
console.log('post:', post);
dispatch({
type: NEW_POST,
payload: post
})
})
}
This is how I call this in component after clicking submit:-
onSubmit = (e) => {
e.preventDefault();
let postData = {
name: this.state.name,
emp_id: this.state.emp_id,
dept: this.state.dept,
gender: this.state.gender,
age: this.state.age,
phone: this.state.phone
}
this.props.createPost(postData);
}
I want to get the response string ('Form saved') but I don't know how to read that. Can anyone help? Thanks in advance
fetch returns a raw response object. To get an expected data you should call a .json() method on raw response object which is returned by fetch, like below:
export const createPost = postData => dispatch => {
fetch(`${Config.address}/post`, {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
})
.then(response => response.json()) // add this line
.then((post) => {
console.log('post:', post); // you should get an object with `Form saved` or something similar to it
dispatch({
type: NEW_POST,
payload: postData // replace it to the input parameter
})
})
}
Using async/await it becomes more readable:
export const createPost = (postData) => async (dispatch) => {
// send postData to server
const rawResponse = await fetch(`${Config.address}/post`, {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
});
// we are done with server but we need one more step
// turn a raw response to readable JS object
const message = await rawResponse.json()
// message from server response
console.log('Message ', message);
// store same object as we sent to server in redux store
dispatch({ type: NEW_POST, payload: postData });
}
Hope it helps