I am trying to POST some variables as part of req.body to a Firebase Cloud Function. I am using the modern fetch() syntax as following:
const { licenseCode } = this.state;
fetch('https://myAPI.com/inputLicense', {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ licenseCode })
})
And here is how my Cloud function looks:
exports.inputLicense = functions.https.onRequest((request, response) => {
// const { licenseCode } = request.body
console.log(request.get('content-type'))
console.log('query', request.query)
console.log('body', request.body)
})
Unfortunately, all of the above logging produces empty objects or undefined in the case of the first line. In a usual Express setup, I know I need to use:
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
But don't know how to do it with cloud functions. Google claims in their Docs they parse my requests automatically, based on the header but I just can't get it to work.
Any help is more then welcome, thanks in advance.
It seems like you solved the problem, but for anyone else having a problem. In my case the problem was the firebase cloud function triggering on the cors preflight request which contains no body.
I solved it by removing the application/json content-type in the fetch call and decoding the json body manually in the cloud function
// on the client
fetch(functionURL + '/' + name, {
body: JSON.stringify({abc: 123}),
method: 'POST',
mode: 'cors',
})
// on the server
functions.https.onRequest(async (req, res) => {
const {abc} = JSON.parse(req.body)
res.set('content-type', 'application/json')
res.set('Access-Control-Allow-Origin', '*')
res.status(200)
res.send({result: abc})
})
I've done some tests and apparently the problem comes from the object destructuring.
The following should work:
const obj = { licenseCode: this.state };
fetch('https://myAPI.com/inputLicense', {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(obj)
})
Related
I am using React + NodeJS & Axios but have been trying to send a post request but experiencing difficulties.
The request seems to be posting successfully, but all actions at the nodejs server is returning in the "undefined" data value, even if the data is passed successfully shown in the console.
REACT
const fireAction = (data1, data2) => {
const data = JSON.stringify({data1, data2})
const url = `http://localhost:5000/data/corr/fire`;
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'AUTHCODE',
}
}
axios.post(url, data, config)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
fireAction("Oklahoma", "Small apartment")
NODE
app.post('/data/corr/fire', async (req, res) => {
try {
const data = req.body.data1;
console.log(data)
} catch(e) {
res.send({success: "none", error: e.message})
}
});
Result of node: "undefined"
I have added the following body parser:
app.use(express.json());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
I am not sure why this error is happening. I see there is similar questions to mine: however none of them are applicable as I'm using both express and body parser which is already suggested.
You're POSTing JSON with a content-type meant for forms. There's no need to manually set content-type if you're sending JSON, but if you want to manually override it, you can use 'Content-Type': 'application/json', and access the response in your route with req.body. If it does need to be formencoded, you'll need to build the form:
const params = new URLSearchParams();
params.append('data1', data1);
params.append('data2', data2);
axios.post(url, params, config);
I am working on a node API with React and Express. Node retrieves the data from Postgress like this:
router.get('/getRestaurants', async(req, res) => {
console.log('Restaurants');
try {
const { rows } = await db.getAllRestaurants();
console.log(rows);
res.json(rows);
} catch(error) {
console.error(`Error ${error}`);
res.status(500).send({message: `API internal error`});
}});
The console.log it shows the data without problem and if I use Postman or Curl it seems to work fine. But when I try to retrieve the data from my frontend React I get this error:
Uncaught (in promise) SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
React makes the POST request like this:
useEffect(() => {
async function fetchData() {
const response = await fetch('http://172.20.0.4:3000/getRestaurants', {
method: 'GET', // *GET, POST, PUT, DELETE, etc.
mode: 'no-cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
});
const data = await response.json();
console.log(data);
return data;
}
fetchData();
});
It's probably not hard to see but there's something I'm missing. Thank you in advance!
I think you have a problem with CORS, since you are fetching data from another origin, you need to set mode: 'cors', which means that you will fetch data across origins. when you set it to mode: 'no-cors' that mean that you don't allow cross origins and that is the cause of the problem. cos as you said. your express app has a different origin than your react app. but it will still not work until you allow your express api, the origin you are fetching from. by setting headers to: ACCESS-CONTROLLE-ALLOW-ORIGIN * and the star * means allow all kind of origins. but if you want to allow a specific origin, replace the
* with url of your react app. you can also use a node.js package that will help you at this in a clean and easy way, example using cors package https://github.com/expressjs/cors:
const cors = require("cors");
let whitelist = ["http://localhost:3000"];
// Middleware
app.use(
cors({
origin: function (origin, callback) {
if (!origin) return callback(null, true);
if (whitelist.indexOf(origin) === -1) {
var message =
"The CORS policy for this origin doesnt " +
"allow access from the particular origin.";
return callback(new Error(message), false);
}
return callback(null, true);
},
})
);
Can anyone spot any problems that may explain why the api client is giving me the forbidden error? I know the credentials are correct, as GET requests w the same info in the url work find.
Thank you in advance
app.get('/translate', (req, res) => {
var textToTranslate = "Hello friend"
const targetLanguage = "ES"
var link = `https://api-free.deepl.com/v2/translate`
var options =
{
method: 'POST',
headers: {
"Host": 'api-free.deepl.com',
"Content-Length": 54,
"Content-Type": 'application/x-www-form-urlencoded',
"User-Agent": "YourApp",
"Accept": "*/*",
},
body: JSON.stringify({
'auth_key': deeplAccessCode,
'text': textToTranslate,
'target_lang': targetLanguage
}),
}
return fetch(link, options)
.then((response) => {
console.log(response)
return response.json(); //Transform http body to json
})
.then((json)=> {
res.send(json) //return json to browser
})
.catch(e => {
console.log(e)
return res.sendStatus(400);
});
})
It's probably failing because you're setting your Content-Type of your body to be application/x-www-form-urlencoded (which is correct as per the DeepL API specification) but then you provide a JSON body (which would require content type to be application/json).
You need to provide a URL-encoded body instead, like the part you can also append to the URL after the ?. See also this answer on SO.
I am running my React js web app in one port 3000.
For node server I am using 4000.
While calling fetch method it returns `400 Bad request'.
Error
POST http://localhost:4006/auth/admin 400 (Bad Request)
react code npm started in 3000 port
fetch('http://localhost:4000/auth/admin',
{ mode: 'no-cors',
method: "POST",
body: JSON.stringify({
username:"admin",
password:"1234"
}),
headers: {
"Content-Type": "application/json",
'Accept': 'application/json, text/plain, */*',
credentials: "omit", //
// "Content-Type": "application/x-www-form-urlencoded",
},
})
.then((response) => console.log(response));
node code running in 4000 port
const passport = require("passport");
const route = require("../constants/routeStrings");
const keys = require("../config/keys");
const processStatus = require("../constants/processStatus");
const success = {
status: processStatus.SUCCESS
};
const failute = {
status: processStatus.FAILURE
};
module.exports = app => {
app.post('/auth/admin', passport.authenticate("local"), (req, res) => {
res.send(success);
});
};
Do not stringify the body. Change from
body: JSON.stringify({
username:"admin",
password:"1234"
}),
to
body: {
username:"admin",
password:"1234"
},
The 400 response is raised by passport since it is unable to read your params. You need to tell your "node" app to parse them before your actual routes.
// Import body parser, you should read about this on their git to understand it fully
const parser = require('body-parser');
const urlencodedParser = parser.urlencoded({extended : false});
// before your routes
app.use(parser .json());
app.use(urlencodedParser) // This will parse your body and make it available for your routes to use
Then do your other calls.
Also, make sure that you are sending username and password keys, otherwise read the documentation on how to change these key names to something else
I suffered long hours, but I overcame it throw writing those lines of code blocks. I successfully send the request to the server's controller, hopefully yours: make it try.
First define a async function to make POST request:
async function _postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
referrerPolicy: 'no-referrer',
headers: {
"Content-type": "application/json; charset=UTF-8"
},
body: JSON.stringify(data)
});
return response.json();
}
Now create a request JSON payload:
let requestPayload = {
propertyName1: 'property value1',
propertyName2: 'property value23',
propertyName3: 'property value',
So on
}
Note: Request model will be your desired model, what request payload you actually send.
Now make a request using this payload including your end point URL:
_postData('http://servername/example', requestPayload )
.then(json => {
console.log(json) // Handle success
})
.catch(err => {
console.log(err) // Handle errors
});
100% worked on my project.
I'm simply trying to post json data to an express server using node-fetch. I know the post function in the server works because I've tested it in git bash. I'm also doing this in a react component.
Here's the fetch code:
addBug(bug) {
let bugsModified = this.state.bugs.slice()
bug.id = this.state.bugs.length + 1
bugsModified.push(bug)
fetch('http://localhost:3000/api/bugs', {method: 'POST', body: bugsModified})
.then(res => res.status === 200 && this.setState({bugs: bugsModified}))
}
The {body: bugsModified} doesn't seem to send the server anything. Here's the code from the server:
app.use(bodyParser.json())
app.post('/api/bugs', (req, res) => {
const bug = req.body
bugs.push(bug)
res.json(bug)
})
app.listen(3000, () => console.log('connected...'))
If anyone can help me figure out how to post actual data using node-fetch, it would be greatly appreciated.
FYI I would ensure that your content headers are populated:
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': new Buffer(body).length
}