nodeJS - make HTTPS request, sending JSON data - json

I would like to send an HTTPS POST from one nodeJS server to another. I have some JSON data I would like to send with this request (populated by a html form).
How can I do this? I am aware of https.request() but there does not seem to be an option to include JSON as a part of the query. From my research it seems possible with an HTTP request, but not an HTTPS request. How can I solve this?
const pug = require('pug');
var cloudinary = require('cloudinary');
var express = require('express');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
var request = require('request');
var bodyParser = require('body-parser');
var options = {
hostname: 'ec2-54-202-139-197.us-west-2.compute.amazonaws.com',
port: 443,
path: '/',
method: 'GET'
};
var app = express();
var parser = bodyParser.raw();
app.use(parser);
app.set('view engine', 'pug');
app.get('/', upload.single('avatar'), function(req, res) {
return res.render('index.pug');
});
app.get('/makeRequest*', function(req, res) {
query = req['query'];
/*
Here, I would like to send the contents of the query variable as JSON to the server specified in options.
*/
});

You can send JSON data through a POST http request with the native https node module, as stated in the documentation
All options from http.request() are valid.
So, taking the http.request() example you can do the following:
var postData = querystring.stringify({
'msg' : 'Hello World!'
});
var options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
var req = https.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
});
// write data to request body
req.write(postData);
req.end();
You should edit postData to your desired JSON object

I believe the below is what you want. Using the request library. See comments in the code for my recommendations.
...
var options = {
hostname: 'ec2-54-202-139-197.us-west-2.compute.amazonaws.com',
port: 443,
path: '/',
method: 'POST',
json: true
};
...
//making a post request and sending up your query is better then putting it in the query string
app.post('/makeRequest', function(req, res) {
var query = req.body['query'];
//NOTE, you cannot use a GET request to send JSON. You'll need to use a POST request.
//(you may need to make changes on your other servers)
options.body = { payload: query };
request(options, function(err, response, body) {
if (err) {
//Handle error
return;
}
if (response.statusCode == 200) {
console.log('contents received');
}
});
});

as matt mentioned you need to use request
to send JSON object not JSON.Stringify so that at the server you can receive it using:
app.post('/makeRequest', function(req, res) {
console.log (req.body.param1);
}
Use the following code:
var request = require("request");
request({
'url':"http://www.url.com",
method: "POST",
json: true,
body: {'param1':'any value'}
}, function (error, resp, body) {
console.log ("check response.");
});

Related

POST Request Body is empty

Task
Parse a CSV file
Send the data to an API enpoint
Save data to MySql database
Problem
The request body is showing up empty when I send data via fetch. However, I can send and see the body data if I use Postman.
I've added a console.log(req.body) and it's printing out {} to the console.
Parse and Send Data to Endpoint
const changeHandler = (event) => {
Papa.parse(event.target.files[0], {
header: true,
skipEmptyLines: true,
complete: function (results) {
results.data.forEach(entry => {
// Create the data object.
let data = {};
let keys = ['Date', 'Description', 'Debit Amount'];
for (let key in entry) {
if (keys.includes(key)) {
data[key.toLowerCase().replaceAll(' ', '_')] = entry[key];
}
}
// Send data to server
fetch('http://localhost:3001/api/create_transactions', {
method: 'POST',
mode: 'no-cors',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
}).then(function (response) {
console.log(response);
})
});
},
});
// Reset file input
event.target.value = null;
};
Save Data to MySql
app.use(express.json());
const crypto = require('crypto');
app.post("/api/create_transactions", (req, res) => {
console.log(req.body);
/*
let hash = crypto.createHash('md5').update(req.body['date'] + req.body['description'] + req.body['debit_amount']).digest('hex');
let data = [
hash,
req.body['date'],
req.body['description'],
req.body['debit_amount'],
];
db.query('insert into transactions (`hash`, `date`, `description`, `debit_amount`) values (?, ?, ?, ?)', data, (err, result, fields) => {
if (err) {
console.log(err);
} else {
console.log(result);
res.send(JSON.stringify({"status": 200, "error": null, "response": result}))
}
});
*/
});
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});
According to this post Fetch: post json data, application/json change to text/plain you can not change the Content-Type to application/json if you are using no-cors. So I will have to enable cors if I want to use fetch.
Using this tutorial https://www.section.io/engineering-education/how-to-use-cors-in-nodejs-with-express/ I was able to enable cors on my nodejs server and receive the proper headers.
Try to use express's bodyParser app.use(express.bodyParser());

Send JSON Data to Google Cloud Functions using Express.js Routing

Can anyone please help me to understand, why am I getting errors while calling the google cloud function, whereas I'm not getting an error if I'm calling the same function locally.
PFB the code of the function, that I'm calling from
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded());
var n1 = null;
var n2 = null;
app.get('/sum', (req, res) => {
n1 = Number(req.query.n1 || req.body.n1);
n2 = Number(req.query.n2 || req.body.n2);
res.json({
"n1": n1,
"n2": n2,
"result": n1 + n2
})
});
app.listen(3000);
exports.calculator = app;
Javascript code of the call made to google cloud function:
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({"n1":1,"n2":2});
var requestOptions = {
method: 'GET',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("https://us-central1-testing-297304.cloudfunctions.net/calculator/sum", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
All the requests either local or to cloud function is made through Postman
Error that is given by gcp:
Calling your function returns "Cannot GET /sum" error because requests with GET/HEAD method cannot have body. What you should to is to change your request to POST (on your code and also your Postman request).
app.post('/sum', (req, res)
and
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
I did that on my test function and I was able to get a 200 OK with an output using Postman.

I am trying to display a html file using res.sendFile in express

i am trying to implement a work flow, where, when the user logs in, the user credentials is posted to one of the routes in express via ajax to check if the user exists, if the user exists, the express route will send back a message "authorised" to the ajax call, and the success callback is invoked where another ajax call sends a header along with data to the express route(/reroute). This express /reroute api is trying to res.redirect to another route /homepage. Inside the /homepage route i am attempting to display a html file using res.sendfile, and the res.sendfile is not working.
my login ajax call
$(document).on("click", "#login", (e) => {
const email = $('#logemail').val().trim();
const pass = $('#password').val().trim();
$.ajax({
url: "http://localhost:4000/checkuserexists",
type: "POST",
dataType: "JSON",
data: {
email: email,
pass: pass
},
success: function(data, textStatus, request) {
console.log(data)
if (data.message === "authorised") {
const token = request.getResponseHeader('access-token');
localStorage.setItem("access-token", token);
$.ajax({
url: "http://localhost:4000/reroute",
type: "GET",
dataType: "JSON",
beforeSend: function(xhr) {
xhr.setRequestHeader('access-token', token);
},
data: {
redirectTo: 'homepage'
},
success: function(data) {
console.log(data + " from ajax ")
}
})
} else {
$('.alertbox').show();
$('.alertbox').text("User unauthorised");
}
}
})
})
my express route (/reroute)
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
if (req.header('access-token')) {
const token = req.header('access-token');
const redirectTo = req.query.redirectTo;
if (redirectTo === 'homepage') {
res.setHeader('access-token', token)
res.redirect('/homepage')
}
}
})
module.exports = router;
my homepage route
const express = require('express');
const path = require('path');
const token_middleware = require('../middlewares/jwtauth');
const router = express.Router();
router.use(express.static(path.join(__dirname, "../public")))
router.get('/', token_middleware, (req, res) => {
if (req.status === "exists") {
res.sendFile(path.join(__dirname, "../public/homepage.html"));
} else {
res.redirect('/');
}
})
module.exports = router;
You're requesting the URL with Ajax.
The browser asks for /reroute and gets a redirect to /homepage.
It then asks for /homepage and gets an HTML document.
It passes that HTML document to the JavaScript engine and jQuery tries to parse it as JSON (it ignores the Content-Type because you said dataType: "JSON") and errors.
If you want to do this with Ajax, then don't redirect. Return some JSON that tells your code the login was successful. Then you can navigate with client-side JS and the location object.
If you want to redirect, then use a regular form submission and not Ajax.

How to receive (and decode) JSON from post data in Node.Js Express?

Suppose I have sent data with the following code:
$.ajax({
type: "POST",
url: "/save/" + #{key},
data: transitions2,
success: function (data) {
},
dataType: "json"
});
where transitions2 is hierarchical JS object.
Now how can I receive it intact at server side
router.post('/save/:key', function(req, res) {
// where is my data here?
});
UPDATE
I found info about body parsers, and found that my site template already contained them. Particularly, app.js contains:
...
var bodyParser = require('body-parser');
...
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/data', express.static(path.join(__dirname, '../data')));
app.use('/', index);
...
So I wrote in my index.js:
...
router.post('/save/:key', function(req, res) {
var transitions = req.body;
image_data.save_transitions(req.params.key, req.query.postfix, transitions);
});
...
Unfortunately, transitions contains
while on client side it contained
i.e. was full of data.
What can be the problem?
UPDATE 2
I tried to do
$.ajax({
type: "POST",
url: "/save/" + #{key},
data: JSON.stringify(transitions2),
success: function (data) {
}
});
and I see in Fiddler2 now, that full Json is passed.
[{"start_image":"20170402_1_NATURAL_COL0R","end_image":"20170409_1_NATURAL_COL0R","transition_classes":["no_transition","some_activity"]},...
Unfortunately, on server side I observe truncated and corrupted string
(equal sign should not be in JSON).
And JSON.parse fails.
use body-parser middleware to retrieve the data.
npm install body-parser
configure this in express app.
Find below the sample code
var bodyParser = require('body-parser');
app.use(bodyParser.json());
Then in your router use the following:
router.post('/save/:key', function(req, res) {
var data = req.body // here is your data
});
The problem was on client side only. Correc way to post complex object with json is:
$.ajax({
type: "POST",
url: "/save/" + #{key},
data: JSON.stringify(transitions2),
contentType: "application/json; charset=utf-8",
success: function (data) {
}
});
stringify and contentType are obligatory.
front:
axios.post('/attack', {
number:number,
count:count
},
{
headers:{contentType: "application/json; charset=utf-8"}
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
}
back:
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.json())
app.post('/attack', (req, res) => {
let data = req.body
console.log(data)
res.send('200')
})
console log: { number: '(number)', count: '(count)' }

Extracting a JSON Object from a URL

We are attempting to extract a JSON Object from a URL through http requesting. However, when we consistently getting the "undefined" when we try to return the text. Is there a problem in the way that we are implementing the http request?
function getUserData(email) {
var pathURL = "/" + email + "/data"
var options = {
host: 'localhost',
port: 3000,
path: pathURL,
method: 'GET',
headers: {
accept: 'application/json'
}
};
var x = http.request(options, function(res){
console.log("Connected");
res.on('data', function(data){
console.log(data);
});
});
}
Close the http.request() by using
x.end();
Here a reference to a similar question.
Sending http request in node.js
Try logging error as:
req.on('error', function(err){
console.log('problem with request:',err.message);
});
Meanwhile check the documentation of http library as well.
The response body are data but not returning to x.
var body = []
request.on('data', function(chunk) {
body.push(chunk)
}).on('end', function() {
body = Buffer.concat(body).toString()
// all is done, you can now use body here
})