Firebase Functions - cannot read req.body - node.js

I'm having a problem with my Firebase Functions https request.
This is my code to trigger it:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.setHeader('Content-Type', 'application/json');
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "GET, POST");
next();
});
app.use((err, req, res, next) => {
if (err instanceof SyntaxError) {
return res.status(400).send();
};
next();
});
app.post('/fetchPosts', (req, res) => {
exports.fetchPosts(req, res);
});
exports.widgets = functions.https.onRequest(app);
const cors = require('cors')({ origin: true })
exports.fetchPosts = (req, res) => {
console.log(req.body)
console.log(res)
let topics = req.body.topics || ['live'];
let start = req.body.start || 0;
let num = req.body.num || 10;
let next = start+num;
// setting up the response.
});
That looks good as far as I can tell..
Now when I do my api call I do:
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Content-Type', 'application/json; charset=UTF-8');
const request = new RequestOptions({ headers: headers });
const url = 'https://my-link.cloudfunctions.net/widgets/fetchPosts';
let payload = {
topics: ["live", "pets"]
}
console.log(JSON.stringify(payload))
this.http.post(url, JSON.stringify(payload), request)
.pipe(map((res:Response) => {
console.log(res.json())
}))
.subscribe(
data => console.log(data),
err => console.log(err),
() => console.log('Got feed')
);
and it just returns topics with just ['live'].. because of the failsafe that I set up on the backend.. but why isn't getting my topics that I'm sending?
Also, when I console.log(req.body) on the backend it just shows {}.. an empty object..
Any ideas why the req.body doesn't seem to work? I do it with start and num as well, but they all revert back to the failsafe.

You must use POST method to handle req.body . In your case, you can handle your variable with req.query
To handle req.body . You can use Postman, then select POST method and post data as JSON . You can read more to use Postman well.

Related

CORS on react request to node.js API

This is my node,js API,that works with no problems using postman, but when I try to make a request from a different origin like a react project the request is blocked
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const port = process.env.PORT || 9000;
const routes = require('./routes/routes');
const token = require('./config/config');
const cors = require('cors')
app.use(cors())
app.use(express.json());
app.use('/api', routes);
app.listen(port, () => console.log('server listening on port', port));
const url = "mongodb://localhost/titles_db";
mongoose.connect(url,{})
.then( () => console.log('DB connected'))
.catch( (e) => console.log('Erorr on db connection'));
and this is the function that is called on my request
searchTitles = (req, res) => {
const terms = req.query.terms;
const format = req.query.format;
titleSchema.find({title: {$regex:terms, $options: 'i'}})
.then( data => {
if(format == 'json')
res.json(data);
else{
res.setHeader("Content-Type", "text/plain");
res.send(data);
}
})
.catch( error => res.json( {message: error}))
}
and here is the function that makes the request on the frontend
const getFieldText = e => {
setTerm({term: e.target.value });
const url = `http://localhost:9000/api/titles/?terms=${e.target.value}&format=json`
fetch(url)
.then(response => console.log(response))
.then(data => console.log(data));
}
even including cors library on node
const cors = require('cors')
app.use(cors())
I get this response
Response { type: "cors", url: "http://localhost:9000/api/titles/?terms=aaaaaa&format=json", redirected: false, status: 403, ok: false, statusText: "Forbidden", headers: Headers, body: ReadableStream, bodyUsed: false }
I added an options array but I have the same result
var corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions))
configure the cross headers like this (in your server node config):
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', "http://localhost:8080");
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, authorization, Access-Control-Allow-Origin');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', 'true');
// Pass to next layer of middleware
next();
});

Message received from background. Values reset

I'm sending post request from "angular->port 4200" to "expressjs server->port 8000".
As an example i'm folowing this example: https://github.com/kuncevic/angular-httpclient-examples/blob/master/client/src/app/app.component.ts
I'm getting two error :
1)undefined from Nodejs(data and req.body.text)
2)Message received from background. Values reset
Angular side:
callServer() {
const culture = this.getLangCookie().split("-")[0];
const headers = new HttpHeaders()
headers.set('Authorization', 'my-auth-token')
headers.set('Content-Type', 'application/json');
this.http.post<string>(`http://127.0.0.1:8000/appculture`, culture, {
headers: headers
})
.subscribe(data => {
});
}
expressjs side:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
var path = require('path');
app.all("/*", function(req, res, next){
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
next();
});
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.post('/appculture', function (req, res) {
var currentCulture = `${req.body.text} from Nodejs`;
req.body.text = `${req.body.text} from Nodejs`;
res.send(req.body)
})
app.listen(8000, () => {
console.log('server started');
})
Either you are not sending anything of there is no value in body.text
Try to console.log(req.body) instead of req.body.text.
Try to console.log(culture) and this.getLangCookie() on the client side to see if you are actually sending something.
You can also make use of the network tab in the browser to inspect the request that you are sending.
Angular side:
callServer() {
const culture = this.getLangCookie().split("-")[0];
const headers = new HttpHeaders()
headers.set('Authorization', 'my-auth-token')
headers.set('Content-Type', 'application/json');
this.http.get(`http://127.0.0.1:8000/appculture?c=` + culture, {
headers: headers
})
.subscribe(data => {
});
}
Nodejs side:
app.get('/appculture', function (req, res) {
currentCulture = req.query.c;
res.send(req.body)
})

Post req.body is always empty object

I'm using Typescript Fetch wrapper to do post and get requests and getting empty object on post(get works fine) (Before I used Vanilla Js and all worked fine)
Nodejs:
const express = require('express');
const fs = require('fs');
const app = express();
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
next();
});
app.use(express.json());
app.post('/login', (req, res) => {
let isLogged = login(req.body);
console.log(req.body);
res.status(200).json(isLogged);
});
My Typescript fetch Wrapper:
async function fetchWrapper<T>(path: string, config: RequestInit): Promise<T> {
const request = new Request(path, config);
const response = await fetch(request);
if (!response.ok) {
throw new Error(
`name: ${response.status}, message: ${response.statusText}`
);
}
// return empty object
return response.json().catch(() => ({}));
}
export async function post<T, U>(
path: string,
body: T,
config?: RequestInit
): Promise<U> {
const init = { method: 'post', body: JSON.stringify(body), ...config };
return await fetchWrapper<U>(path, init);
}
my post request:
const res = await fetch.post(`${url}/login`, {
body: inputData,
headers: { 'Content-Type': 'application/json' },
});
input data is not empty
The problem here that you are using wrong Content-Type header value. express.json parses application/json content type, while you are sending application/x-www-form-urlencoded. The solution is either to change the content-type you are sending, or add another middleware like bodyparser to parse application/x-www-form-urlencoded body.

Node js CORS failure

I have been trying to build a web application using NODE and React without Express router but I am getting a lot of issues with the CORS part since both node and react are running on different ports. I don't want to use express in this case since i want to use native http module provided by node, hence I am unable to use CORS middleware which is in the npm library.
I have tried every possible solution which would work for resolving the CORS issue but I am at a dead end now. I have shared my server side code below.
/*
* Main server file
*/
//Depenedencies
let https = require('https');
let url = require('url');
let fs = require('fs');
let handlers = require('./lib/handlers');
let stringDecoder = require('string_decoder').StringDecoder;
let decoder = new stringDecoder('utf-8');
//server object definition
let server = {};
//https certifications
server.certParams = {
'key': fs.readFileSync('../lib/Certificates/serverKey.key'),
'cert': fs.readFileSync('../lib/Certificates/serverCert.crt')
};
server.https = https.createServer(server.certParams, (req, res) => {
server.unifiedServer(req, res);
});
//main server
server.unifiedServer = (req, res) => {
//converting url to url object
let parsedUrl = url.parse("https://" + req.rawHeaders[1] + req.url, true);
//constructing required params for handlers
let method = req.method;
let route = parsedUrl.pathname;
let queryStringObject = parsedUrl.query;
let headers = req.headers;
//function specific params
let requestBodyString = "";
let chosenHandler;
let requestObject = {};
let responsePayload = {
'Payload': {},
'Status': ""
};
//streaming in the req body in case of post req
req.on("data", function(chunk) {
requestBodyString += chunk;
});
//this is called regardless of the method of the req
req.on("end", function() {
//this is specific to post req
requestBodyString += decoder.end();
requestBodyString = method == "POST" ? JSON.parse(requestBodyString) : {};
//the request object sent to the handlers
requestObject.method = method;
requestObject.reqBody = requestBodyString;
requestObject.queryObject = queryStringObject;
chosenHandler = server.handlers[route] ? server.handlers[route] : server.handlers.notFound;
let headers = {
"Access-Control-Allow-Origin" : "https://localhost:3000/",
"Access-Control-Allow-Methods" : "OPTIONS, POST, GET",
"Access-Control-Allow-Headers" : "Origin, Content-Type"
};
chosenHandler(requestObject)
.then((result) => {
//post handler call
responsePayload.Status = "SUCCESS";
responsePayload.Payload = result;
//send the data back
res.writeHead(200,headers);
res.write(JSON.stringify(responsePayload));
res.end();
}).catch((error) => {
//error handler
responsePayload.Status = "ERROR-->" + error;
//send the data back
res.writeHead(200,headers);
res.write(JSON.stringify(responsePayload));
res.end();
});
});
};
//router definition
server.handlers = {
'/login': handlers.login,
'/signup': handlers.signup,
'/checkUserName': handlers.checkUserName,
'/checkEmail': handlers.checkEmail,
'/notFound': handlers.notFound
};
//init function
server.init = () => {
//start the https server
//TODO--> Change this to handle changing port and env
server.https.listen(5000, function() {
console.log('The https server is listening on port 5000 in Development mode');
});
};
//export the module
module.exports = server;
I am making a post request to test the connection but I am getting this evertime:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:5000/login. (Reason: CORS request did not succeed).
Can anyone please tell me what am I doing wrong?
Set the "Access-Control-Allow-Origin" header in the response stream object.
Try with the below snippet -
server = http.createServer(function(req,res){
// Set CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Request-Method', '*');
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
res.setHeader('Access-Control-Allow-Headers', '*');
if ( req.method === 'OPTIONS' ) {
res.writeHead(200);
res.end();
return;
}
// ...
});
OR it that does not work, try using -
res.setHeader('Access-Control-Allow-Headers', req.header.origin);
Use this middle ware after let decoder = new stringDecoder('utf-8');
var express = require('express');
var app = express();
var allowCrossDomain = function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
res.header('Access-Control-Allow-Credentials', 'true');
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.status(200).send();
} else {
next();
}
};
app.use(allowCrossDomain);
This is relevent for express framework.

incomplete response received from application nodejs

I'm using nodejs on nginx server. Sometimes the node app is crashing and returning 'incomplete response received from application'. What is causing this problem?
const Express = require('express');
const BodyParser = require('body-parser');
const Request = require('request');
const Conf = require('./conf');
const {db} = require('./lib/database');
const app = Express();
app.use(BodyParser.json());
app.use(BodyParser.urlencoded({extended: false}));
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Access-Control-Allow-Methods', 'POST');
if ('OPTIONS' == req.method) {
res.header('Access-Control-Allow-Methods', 'POST');
return res.sendStatus(200);
}
next();
});
app.post('/getProperty', (req, res) => {
const sql = "SELECT ('['||(st_asgeojson(geom)::json)||']')::json FROM spt.spt where id=" + req.body.id;
db.query(sql, (err, result) => {
if (err) res.status(err.code).json({code: err.code, message: err.message}).end();
(result.rows.length == 0) ? res.send([]) : res.send(result.rows[0].json);
})
});
app.post('/getAnalysis', (req, res) => {
const sql = "select value from test.test where id=" + req.body.id + " order by value asc";
db.query(sql, (err, result) => {
if (err) result.status(err.code).json({code: err.code, message: err.message}).end();
res.send(result.rows);
})
});
app.listen(3000);
If an error occurs, your code tries sending a response twice. You need to exit the function after sending the error response to the client, so either use return in your if or add an else below for the success response.
Sending multiple responses will dicsonnect the socket in express.

Resources