I have an express service which has an endpoint that consumes a POST call with form-data in XML.
Postman Call
I'm using multer and express-xml-bodyparser and my index.js looks like:
'use strict';
const express = require('express');
const app = express();
const xmlparser = require('express-xml-bodyparser');
const multer = require('multer')
const upload = multer()
const redact = { redact: ['body.*', 'value.body'] };
const modsRoute = require('./routes/mods');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(xmlparser());
app.use(upload.none());
app.post('/request', modsRoute.postMethod)
module.exports = app;
The problem is that when I try to print the content of the request body in my router method:
const postMethod = async (req, res, next) => {
try {
console.log('body: ', req.body);
res.status(200).send();
} catch (err) {
next(err);
}
};
I get a weird object:
body: [Object: null prototype] {
'api-key': '1a393779-c191-11e3-ae50-80c16e6a4098',
data: '<subscriber>\n' +
'\t<action>add</action>\n' +
'\t<customer_id>529</customer_id>\n' +
'\t<subscriber_details>\n' +
' <unique_id>123UniqueID</unique_id>\n' +
'\t\t<firstname>First</firstname>\n' +
'\t\t<lastname>Test</lastname>\n' +
'\t\t<address1>999 Street</address1>\n' +
'\t\t<address2></address2>\n' +
'\t\t<city>Scottsdale</city>\n' +
'\t\t<state>AZ</state>\n' +
'\t\t<zip>85253</zip>\n' +
' <email>email#infoarmor.com</email>\n' +
' <dob_month>00</dob_month>\n' +
'\t\t<dob_day>00</dob_day>\n' +
'\t\t<dob_year>0000</dob_year>\n' +
'\t\t<phone>9999999999</phone>\n' +
'\t\t<options>\n' +
'\t\t\t<plan_type>1</plan_type>\n' +
' <ew_status>0</ew_status>\n' +
'\t\t</options>\n' +
'\t\t<billing_information>\n' +
'\t\t\t<bill_type>prd</bill_type>\n' +
'\t\t</billing_information>\n' +
'\t</subscriber_details>\n' +
'</subscriber>'
}
As it can be seen, the object contains all the newline and whitespace characters and it hasn't really converted it into JSON.
I also tried to convert the whole body into JSON with JSON.parse() but I got an exception thrown. I also tried to first stringify() the body and then parse it.
In that case, I could only get the data field but I was again an expection when trying to get the api-key field.
Do I need to add any other middleware in order to get at least a correct JSON object of req.body even though the field data is still in XML and not JSON?
You can send json data to user using like this
const postMethod = async (req, res, next) => {
try {
res.json({"Hello":"World"});
// you can send anything json back including req.body like
// this res.json(req.body);
} catch (err) {
next(err);
}
};
Related
At the end of the waterfall-dialog in "summary" (i.e., the last if statement) i want to automatically make a post request without making an API call in Postman, is eventListener the way? How to include it?
async summaryStep(step) {
if (step.result) {
// Get the current profile object from user state.
const userProfile = await this.userProfile.get(step.context, new UserProfile());
userProfile.name = step.values.name;
//the same for other step values(email, doctor, date)
let msg = `you want a date with dr. ${userProfile.doctor} , and your name is ${userProfile.name}.`;
if (userProfile.date !== -1) {
msg += `you have an appointment the: ${userProfile.date}.`;
}
await step.context.sendActivity(msg);
let msg1 = `"${userProfile.date}"`;
if (msg1) {
let z = JSON.stringify(userProfile.name);
//and also the other rows to go in the database(email, doctor, date)
var name = JSON.parse(z);
//and also the other rows to go in the database(email, doctor, date)
//this actually works but only if i use postman
var urlencoded = bodyparser.urlencoded({ extended: false });
app.post('/id', urlencoded, (req, res) => {
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
mysqlConnection.query("INSERT INTO users(name, email, doctor, date) VALUES('" + userProfile.name + "','" + userProfile.password + "','" + userProfile.doctor + "','" + userProfile.date + "')", function (err, result, rows) {
if (err) throw err;
console.log("Yeah! record inserted");
console.log(name);
res.send(result);
});
});
const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Listening on port ${port}..`));
}
} else {
await step.context.sendActivity('Thanks. Your profile will not be kept. Push enter to return Menu');
}
return await step.prompt(CONFIRM_PROMPT3, `is that true? ${step.result}`, ['yes', 'no']);
// this if statement should "fire" the post request...
if (step.result == 'yes') {
return await step.context.sendActivity(`we will contact you soon ${userProfile.password}.`);
}
return await step.endDialog();
}
Per my understanding , you want to know how to call an POST API from Azure bot async function. Pls try the code below in your async summaryStep function to send the post request based on your requirement.
var rp = require('request-promise');
var options = {
method: 'POST',
uri: 'http://localhost:8080/id',
body: {
fieldCount:0,
affectedRows:1,
//your other body content here...
},
json: true,
headers: {
'content-type': 'application/json' //you can append other headers here
}
};
await rp(options)
.then(function (body) {
console.log(body)
})
.catch(function (err) {
console.log(err)
});
}
Hope it helps .
A
nd if there is any further concerns or misunderstand , pls feel free to let me know.
The answer is to move your app.post API endpoint to your index.js file where your bot is already running on a server. Simply spin up a new "server" and "port" making the endpoint available. Then, in your summaryStep (axiosStep in my example), make your API call using Axios, request-promise, or what have you, to post your data. When the API is hit, the data will be passed in and processed.
In the code below, when the API is hit the passed in data is used in a sendActivity posted back to the bot. In your case, your passed in data would be used for the database call in which you could use the returned response in the sendActivity.
Your code would look something like the following. Please note, the post actions are simplified for the sake of the example. You would need to update the post actions to make your mySql queries. This sample also makes use of restify for the server (standard for Bot Framework bots) and uses the same port as the bot, but this can easily be updated to use Express and/or another port.
Hope of help!
index.js
[...]
const conversationReferences = {};
const bodyParser = require('body-parser');
server.post('/id', async (req, res) => {
const { conversationID, data, name } = req.body;
const conversationReference = conversationReferences[ conversationID ];
await adapter.continueConversation(conversationReference, async turnContext => {
var reply = `${ data }. Thanks, ${ name }`;
await turnContext.sendActivity(reply);
});
res.writeHead(200);
res.end();
});
mainDialog.js
async axiosStep ( stepContext ) {
const conversationID = stepContext.context.activity.conversation.id;
try {
const response = await axios.post(`http://localhost:3978/id`, {
data: "Yeah! Record inserted",
name: "Steve",
conversationID: conversationID
})
console.log(response);
} catch (error) {
console.log(error);
}
return stepContext.next();
}
Below is an example of converting a text to qr code.
var QRCode = require('qrcode');
var express = require('express');
var connect = express();
connect.get('/', function(req, res){
res.writeHead(200, { 'Content-Type': 'text/html' });
var sometext='hi my name is saurav ghadai';
// QRCode.QRCodeDraw.color.dark = '#d4d4d4';
QRCode.toDataURL(sometext, function (err, url) {
if (err) console.log('error: ' + err)
res.end("<!DOCTYPE html/><html><head><title>node-qrcode</title></head><body><img src='" + url + "'/></body></html>");
});
});
connect.listen(3030);
console.log('test server started on port 3030');
like this how can we create qr code for a json object ?
You can use JSON Strigify method to convert your JSON object into text. Then use the text output into your QR generator method
I am parsing my json on end but I am still receiving this error.
'use strict';
const http = require('http');
const tools = require('./tools.js');
const server = http.createServer(function(request, response) {
console.log("received " + request.method + " request from " + request.headers.referer)
var body = "";
request.on('error', function(err) {
console.log(err);
}).on('data', function(chunk) {
body += chunk;
}).on('end', function() {
console.log("body " + body);
var data = JSON.parse(body); // trying to parse the json
handleData(data);
});
tools.setHeaders(response);
response.write('message for me');
response.end();
});
server.listen(8569, "192.168.0.14");
console.log('Server running at 192.168.0.14 on port ' + 8569);
Data being sent from the client:
var data = JSON.stringify({
operation: "shutdown",
timeout: 120
});
I successfully receive the json but I am unable to parse it.
Update:
I've updated the code to include the server code in its entirety.
To be perfectly clear, using the following code:
....
}).on('end', function() {
console.log("body " + body);
var json = JSON.parse(body); // trying to parse the json
handleData(json);
});
I get this:
However, this:
....
}).on('end', function() {
console.log("body " + body);
//var json = JSON.parse(body); // trying to parse the json
//handleData(json);
});
produces this
Can we see the server code, please?
Here is a working end-to-end example which is (more or less) what you are attempting, I believe.
"use strict";
const http = require('http');
/********************
Server Code
********************/
let data = {
operation: 'shutdown',
timeout: 120
};
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify(data));
res.end();
});
server.listen(8888);
/********************
Client Code
********************/
let options = {
hostname: 'localhost',
port: 8888,
path: '/',
method: 'POST',
headers: {
'Accept': 'application/json'
}
};
let req = http.request(options, res => {
let buffer = '';
res.on('data', chunk => {
buffer += chunk;
});
res.on('end', () => {
let obj = JSON.parse(buffer);
console.log(obj);
// do whatever else with obj
});
});
req.on('error', err => {
console.error('Error with request:', err);
});
req.end(); // send the request.
It turns out that as this is a cross-origin(cors) request, it was trying to parse the data sent in the preflighted request.
I simply had to add an if to catch this
....
}).on('end', function() {
if (request.method !== 'OPTIONS') {
var data = JSON.parse(body);
handleData(data);
}
});
Further reading if you're interested: HTTP access control (CORS)
Put the identifiers in quotes.
{
"operation": "shutdown",
"timeout": 120
}
http://jsonlint.com/ Is a helpful resource.
I am working on a MEAN stack app, and I'm trying to create a couple of API endpoints that the Angular client can $http.get, with simple JSON files populated with dummy data.
Here's the orders.json file I'm trying to test it with:
[
{
"order_status":"Shipped",
"order_qty":30
},
{
"order_status":"Shipped",
"order_qty":6
}
]
For example, the api route to $http.get:
apiRouter.get('/:fileName', queries.getStaticJSONFileForDevelopment);
But when I try to use express's sendFile method with a local .json file, like orders.json:
queries.js:
exports.getStaticJSONFile = function(req, res) {
var fileName = req.params.fileName;
console.log('path: ' + path.normalize(__dirname + '/' + fileName));
res.sendFile(path.normalize(__dirname + '/' + fileName), function(err) {
if (err) return res.send({ reason:error.toString() });
});
};
The console.log tells me I'm pointed at the correct path to the file, but Postman delivers this error:
TypeError: undefined is not a function
at Object.exports.getStaticJSONFile [as handle] (path/to/queries.js:260:7)
// queries.js:260:7 points to the 's' in 'sendFile' above
However, when I just send the json data by itself:
res.send([{"order_status":"Shipped","order_qty":30},{"order_status":"Shipped","order_qty":6}]);
...the endpoint renders the data as you would expect. Am I trying to get the sendFile method to do something it's not meant to do, or is there something I'm missing? Thanks very much for any advice you may have!
If You want to read json file and response with json so You can try this:
var jsonfile = require('jsonfile');
exports.getStaticJSONFile = function(req, res) {
var fileName = req.params.fileName;
var file = path.normalize(__dirname + '/' + fileName);
console.log('path: ' + file);
jsonfile.readFile(file, function(err, obj) {
if(err) {
res.json({status: 'error', reason: err.toString()});
return;
}
res.json(obj);
});
};
I use express router to catch a ajax post data, which is a stringified JSON obj:
router.all('/ajax/setup/save/asset', function (req, res) {
console.log('POST: /ajax/setup/save/asset');
var fileName = path.join(jsonFileNamePrefix, jsonFileName_asset);
req.on('data', function(chunk) {
console.log('POST: DATA: ' + chunk);
fd = fs.openSync(fileName, 'w');
console.log('Opened file: ' + fileName);
fs.writeSync(fd, chunk);
console.log('Wrote ' + chunk + ' into file ' + fileName);
fs.closeSync(fd);
console.log('Closed file: ' + fileName);
res.end();
console.log('res.end()');
});
});
Then the console logs:
POST: /ajax/setup/save/asset
POST: DATA: {"asset":"test"}
Opened file: /srv/data/asset.json
Wrote {"asset":"test"} into file /srv/data/asset.json
Closed file: /srv/data/asset.json
res.end()
However, the file is actually written as:
[123,34,97,115,115,101,116,34,58,34,116,101,115,116,34,125]
Tried telling fs.writeSync to use 'utf8', 'hex' encoding, still got same result.
Also tried JSON.parse and then JSON.stringify the incoming data chunk, didn't help either..
The req object in your code is actually an instance of the http.IncomingMessage stream.
When it provides information via the data event, this information is provided as a buffer.
Additionally, not all the data for the request is guaranteed to be available in the first call to the handler.
There are several ways to capture this data into a useable string. You could create a new string and simply concat the chunks together
router.all('/ajax/setup/save/asset', function (req, res) {
var buf = ''
req.on('data', function(chunk){
buf += chunk.toString();
});
req.on('end', function(){
console.log(buf);
});
});