Correct way to respond to client on Node.js? - node.js

This being my first attempt at building a server...
I have set up a server to handle a contact form submission that also includes a predefined captcha string.
When the server receives the contact form, if the captcha string is the one expected then I want it to simply respond with a JSON of the parsed contact form query using response.end(JSON.stringify(parsedURL));
If the captcha string is wrong, I want the server to respond "saying" the captcha was wrong, so that the client asks the user to try again. But I don't know how to do that.
ON THE SERVER :
var httpServer = http.createServer(function (request, response)
{
if (/\/contactform\?....../.test(request.url))
{
var parsedURL = url.parse(request.url, true);
var name = parsedURL.query.name;
var email = parsedURL.query.email;
var subject = parsedURL.query.subject;
var enquiry = parsedURL.query.enquiry;
var captcha = parsedURL.query.captcha;
if (captcha !== "testing")
{
// send a "bad" response to the client and include the message "bad captcha"
}
else response.end(JSON.stringify(parsedURL.query));
}
}).listen(8080);
ON THE CLIENT :
$.ajax({
url: "/contactform?..............",
success: function(msg)
{
console.log(msg);
},
error: function(msg)
{
// the "bad captcha" response should be handled here right ?
console.log(msg); // which should be equivalent to console.log("bad captcha");
}
});
When I use response.end(JSON.stringify(parsedURL)); the client (jQuery) considers that a "success".
How should I respond from the server so that the "error" part of the ajax request on the client is executed?
Or is the "error" part supposed to handle only cases where the server doesn't respond at all, i.e. when something has gone horribly wrong server-side, like an exception, a real error, and not cases where simply my evaluation on the server doesn't have the expected outcome ?
Should I instead useresponse.end(...); in both cases as in :
ON THE SERVER :
var httpServer = http.createServer(function (request, response)
{
if (/\/contactform\?....../.test(request.url))
{
var parsedURL = url.parse(request.url, true);
var name = parsedURL.query.name;
var email = parsedURL.query.email;
var subject = parsedURL.query.subject;
var enquiry = parsedURL.query.enquiry;
var captcha = parsedURL.query.captcha;
var response = JSON.stringify(parsedURL.query);
if (captcha !== "testing") response = "bad captcha";
response.end(response);
}
}).listen(8080);
ON THE CLIENT :
$.ajax({
url: "/contactform?..............",
success: function(msg)
{
console.log(msg); // msg will either be the stringified object or "bad captcha"..
}
});
In other words, when a request is successfully received on the server but the server wants to let the client know that something was missing or whatever, should the response from the server be sent as an "error" (i.e. handled by the "error" block on the client's ajax code) or as a "success" with the appropriate message saying what actually happened?

I think what you need to do is set headers of your response.
Here is an example:
var body = 'Sorry!';
response.writeHead(404, {
'Content-Length': body.length,
'Content-Type': 'text/plain' });
Refer to http://nodejs.org/api/http.html#http_response_writehead_statuscode_reasonphrase_headers for more information.

Related

Node and Twilio integration

I have written a programmable SMS feature using Twilio in nodejs. I have a message that has options to select and when user sends back any response I want to send an automated response using twilio.
I have completed all except after processing the response from user my automated response is not being delivered to user.
I keep getting above thing from my twilio dashboard.
Here is my response handler code..
app.post('/ui/sms',function(req, res) {
//req.headers['Content-type'] = 'text/xml';
//req.headers['Accept'] = 'text/xml';
try {
console.log('Processing Response', req.headers);
const MessagingResponse = require('twilio').twiml.MessagingResponse;
const twiml = new MessagingResponse();
const fromTwilio = isFromTwilio(req);
console.log('isFromTwilio: ', fromTwilio);
if (fromTwilio) {
let msg = req.body.Body||'';
if (msg.indexOf('1')>-1) {
twiml.message('Thanks for confirming your appointment.');
} else if (msg.indexOf('2')>-1) {
twiml.message('Please call 408-xxx-xxxx to reschedule.');
} else if (msg.indexOf('3')>-1) {
twiml.message('We will call you to follow up.');
} else {
twiml.message(
'Unknown option, please call 408-xxx-xxxx to talk with us.'
);
}
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(twiml.toString());
}
else {
// we don't expect these
res.status(500).json({ error: 'Cannot process your request.' });
}
/*processSMSResponse(req, function(response) {
res.json(response);
});*/
} catch(e) {
res.json(e);
}
});
function isFromTwilio(req) {
console.log('REQ HEADER:::::::::\n', req);
// Get twilio-node from twilio.com/docs/libraries/node
const client = require('twilio');
// Your Auth Token from twilio.com/console
const authToken = 'xxxxxxxxxxxxxxxxx';
// The Twilio request URL
//const url = 'https://mycompany.com/myapp.php?foo=1&bar=2';
const url = 'https://xxxx.com/ui/sms';
var reqUrl = 'https://xxxx.com/ui/sms'
// The post variables in Twilio's request
//const params = {
//CallSid: 'CA1234567890ABCDE',
//Caller: '+14158675310',
//Digits: '1234',
//From: '+14158675310',
//To: '+18005551212',
//};
const params = req.body;
console.log('post params: ', params);
// The X-Twilio-Signature header attached to the request
try{
Object.keys(params).sort().forEach(function(key) {
reqUrl = reqUrl + key + params[key];
});
var twilioSignature = crypto.createHmac('sha1', authToken).update(Buffer.from(reqUrl, 'utf-8')).digest('base64');
//const twilioSignature = req.header('HTTP_X_TWILIO_SIGNATURE');
console.log('twilioSignature: ', twilioSignature);
} catch(e){
console.log(e);
}
return client.validateRequest(
authToken,
twilioSignature,
url,
params
);
}
I have explicitly tried setting headers but no use. I'm clue less on what twilio expects from me or how to modify headers.
{
"status": "Error",
"error": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Message>Please call 408-xxx-xxxx to reschedule.</Message></Response>"
}
I see this as body in Twilio console and it has the response that I need but could not send as a message..
Twilio Developer Evangelist here.
From looking at your code and trying it myself I can't see anything generally wrong with it. There are two potential failing points here though:
1) I can't see your isFromTwilio function. If that one fails it might cause an error and then return JSON instead of XML on your error handler. I don't know why it would reply with the TwiML in that JSON though.
2) The other behavior I could reproduce (except that the TwiML is not being sent in the response body) is when I don't include body-parser in the middleware chain. This will cause req.body to be undefined and therefore req.body.Body will throw an error that is then being caught and JSON is being returned.
Do you have body-parser included and properly included as a middleware? You can either do it this way:
const { urlencoded } = require('body-parser');
app.use(urlencoded({ extended: false });
or if you only want to use it for this one endpoint you can add urlencoded({ extended: false }) as an argument before your request handler:
app.post('/ui/sms', urlencoded({ extended: false }), function(req, res) {
I hope this helps.
Cheers,
Dominik

twilio say something to caller (node.js)

Hey guys I am working on something and have following Problem :
ACTUAL AIM - If someone calls, I want to let the voice say: "Try to reach someone" and then call some numbers out of an array. ( cant do that atm because i need to fake a call )
ATM AIM - Thats why I at least want to say something to the one who answers the twilio call, that I can be sure it "would" work.
So i faked a call by sending the url that twilio would send (if it gets a call) via a localhost http server. So far so good, my phone gets called. But the woman dont say what I wanted her to say... She sais : Thank you for trying our documentation and then waiting music is following.
AND: The call.status is ALLWAYS queued, or I dont catch it at the right place :/ , Remember my phone is ringing so it should have at least the status ringing ...
This is what I have at the moment:
requestHandler.js:
var querystring = require("querystring");
var emergency = require("./emergency");
var twilio = require('twilio');
function callRequest(response) {
var resp = new twilio.TwimlResponse();
resp.say({voice:'woman'}, 'ahoy hoy! Testing Twilio and node.js');
console.log("call incomming ! EMERGENCY 1 1 11 !");
//emergency.handleIncommingCall();
response.writeHead(200, {"Content-Type": "text/xml"});
response.end(resp.toString());
}
exports.callRequest = callRequest;
server.js:
var http = require("http");
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(handle, pathname, response, request);
}
http.createServer(onRequest).listen(1337);
console.log("Server has started");
}
exports.start = start;
exports.http = http;
router.js:
function route(handle, pathname, response, request) {
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname](response, request);
}else{
console.log("No request handler found for " + pathname);
response.writeHead(404, {"Content-Type": "text/html"});
response.write("404 Not found");
response.end();
}
}
exports.route = route;
index.js:
var server = require("./server");
var router = require("./router");
var requestHandler = require("./requestHandler");
var handle = { };
handle["/demo.twilio.com/welcome/voice/"] = requestHandler.callRequest;
server.start(router.route, handle);
emergency.js:
var twilio = require('twilio');
var accountSid = 'cant tell ya';
var authToken = "cant tell ya";
var client = require('twilio')(accountSid, authToken);
var firstCascadeNumber = "cant tell ya";
var secondCascadeNumber;
var privateNumber; //enter privateNumber here
var twiml = new twilio.TwimlResponse();
function handleIncommingCall (){
//twilio should say : we contact team internet pls wait
//twilio should make music
call(1,firstCascadeNumber);
//cb if staus ist nicht rangegangen call(2)
}
function call (cascade,cascadeNumber){
client.makeCall({
url: "http://demo.twilio.com/docs/voice.xml",
to: cascadeNumber,
from: "cant tell ya"
}, function(err, call) {
if(err){
console.log("ERROR:", err.message);
}else{
console.log("calling " + cascadeNumber);
console.log("status: " + call.status);
if(cascade == 1){
//twiml.say("Hello this i a test. Thank you for calling.");
console.log("should say what i want it to say ! god damn it ");
console.log("status: " + call.status);
//if user geht ran
//startConference()
//if user geht nicht ran
//call(2,secondCascadeNumber)
}else if(cascade == 2){
//if user geht ran
//startConference()
//if user geht nicht ran
//inform caller that no one is there
}else{
console.log("Error: cascade doesnt exsist");
}
}
});
}
function openConference(call,from,to){
//call.joinConference([roomName, option, cbOnEnd])
}
exports.handleIncommingCall = handleIncommingCall;
Twilio developer evangelist here.
You're most of the way there, but you've not quite set your application out right here.
When you make the call, the callback you get only refers to whether the call started correctly. It is not a callback that you need to return TwiML to in order to tell Twilio what to do with the call.
Instead, what happens is when Twilio makes the call, it will send an HTTP request to the URL you supply when you make the call in the first place. That URL should be in your application and available to Twilio.
This blog post on using Twilio with Node.js should be able to show you what I mean by all of that and set you up with a good way of testing this locally too.
Edit
Thanks for updating your code.
Your problem is that you are not telling Twilio to ask you what to do with the call once it connects.
When you create a call with the API you need 3 parameters, the number to call, the number to call from and a URL. When Twilio connects the call it will make an HTTP request to the URL you supply asking what to do next and this is where you supply some TwiML to tell Twilio what to do with the call.
Currently you are supplying this URL: http://demo.twilio.com/docs/voice.xml
If you click through the demo Twilio URL there, you will see the TwiML that is being returned and why you hear a message you are not expecting. Because the URL is not yours, your application cannot take control of the call.
You need to send a URL that points at a route in your application, and that route needs to respond with the TwiML you want. You can expose your local server to Twilio using a tool called ngrok which will allow you to test this.
I recommend you follow the tutorial I linked before, this tutorial on using ngrok to text your incoming HTTP requests from Twilio and this tutorial on creating a click to call application with Twilio.
In the case of your application, instead of trying to handle "/demo.twilio.com/welcome/voice/" which is not a URL you have control of, you should handle, say:
var handle = { };
handle["/calls"] = requestHandler.callRequest;
and then use ngrok to create a tunnel to your application and pass the URL to client.makeCall like this:
function call (cascade,cascadeNumber){
client.makeCall({
url: "http://YOUR_NGROK_SUBDOMAIN.ngrok.io/calls",
to: cascadeNumber,
from: "cant tell ya"
}, function(err, call) {
if (err) {
console.log("Call could not be made", err);
} else {
console.log("Call created successfully. Call ID:", call.sid);
}
}
}
Let me know if that helps.

Node.js blockchain bitcoin api

So I want to use this: (taken from their API site -> node.js documentation)
https://github.com/blockchain/api-v1-client-node
Recieving payments:
https://github.com/blockchain/api-v1-client-node/blob/master/docs/Receive.md
var blockchain = require('blockchain.info');
var identifier = 'myidentifier';
var password = 'mypassword';
var myWallet = new blockchain.MyWallet(identifier, password);
var myBTCadress = '14Q3ufL1BUHtWskBKtsshVDATRY65TaJMB';
Ok, so the recieving part:
var receive = new blockchain.Receive( [confirmations: 1], ? ); // What do I need to put here?
Documentation says:
callbackURL: the url to which the callback should be sent (string)
I don't understand what URL it should go to?!
The callback URL should be the one that redirects back to your site. So setup a callback url with blockchain like...
https://www.yoursite.com/callback/blockchain
Assuming you are using something like express in your app make a route like so.
app.get('/callback/blockchain', function (req, res) {
// Stuff here
});
you will prob need to include
var https = require('https');
That way then you can set up your logic inside for example...
// Stuff here
var options = {
host : 'api.blockchain.info',
path : '/some/path/',
port : 443,
method : 'GET'
}
var request = https.request(options, function(response){
var body = ""
response.on('data', function(data) {
body += data;
});
response.on('end', function() {
res.send(JSON.parse(body));
});
});
request.on('error', function(e) {
console.log('Problem with request: ' + e.message);
});
request.end();
That will for example output you request in json on whatever page you have your app.get('whateverurl') set to.

How to receive ZMQ message inside Express middleware?

I want to send ZMQ message inside app.get but when running I throw error:
events.js:72
throw er; // Unhandled 'error' event
^
ReferenceError: res is not defined
My running code:
var zmq = require('zmq'),
zreq = zmq.socket('req'),
app = express();
zreq.connect('tcp://localhost:5559');
zreq.on('message', function (msg) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.send(msg);
});
app.get('/words', function (req, res) {
zreq.send('nodejs');
//I think it should have something like zreqCallback(req)?
});
The problem is, as the error indicates, that you don't have access to the res object from the message event handler on your req socket. What you need is a way to link the message in that event handler to your res object. You're not going to be able to do that (easily) without support from the other end of that socket.
The basic idea is to associate a unique id with each message you send over zmq and include it in the message sent through the req socket and the reply that comes back from the rep socket. Then also associate the res object with the same message id.
I usually use node-uuid for unique id generation. You'll also need a way to easily encode / decode your messages (it looks like you're just sending straight strings at the moment). The built in JSON parser works fine for that, or you could use something more compact like bencode or protobuf. Be sure to pick something that both ends of the socket can work with.
You're code would look something like this:
Note: I'm assuming we're using node-uuid and JSON. Also, I'm not putting any error handling or sanity checks in here; don't forget that stuff.
var zmq = require('zmq'),
uuid = require('node-uuid'),
zreq = zmq.socket('req'),
app = express();
var responses = {};
zreq.connect('tcp://localhost:5559');
zreq.on('message', function (data) {
data = JSON.parse(data);
var msgId = data.id;
var res = responses[msgId];
res.writeHead(200, { 'Content-Type': 'application/json' });
res.send(data.message);
responses[msgId] = null;
});
app.get('/words', function (req, res) {
var msgId = uuid.v4();
var data = { id: msgId, message: 'nodejs' };
responses[msgId] = res;
zreq.send(JSON.stringify(data));
});
On the other end (I'll just assume it's also written in node for the purpose of this example):
var zmq = require('zmq');
zrep = zmq.socket('rep');
zrep.bind('tcp://localhost:5559');
zrep.on('message', function(data) {
data = JSON.parse(data);
var msgId = data.id;
var msg = data.message;
// Do whatever you were doing before to process the message
// We'll say it ends up in a "results" variable
var response = { id: msgId, message: results };
zrep.send(JSON.stringify(response));
});

ExpressJS - contact external API

Here is the thing :
I have a client which sends data to a server. This server has to contact an external A.P.I. and send back its response to the client. I just can't figure out how and where I can contact the external A.P.I once the server has got the client data.
I route client data like this :
app.post('/getAutoComplete', routes.read);
routes.read retrieves the data within req.body. With my nodejs version (without express framework), I then request the api this way :
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
The problem is that i'd like to use native expressJS method like app.post but I don't know how because :
Express (app) object is not available here (declared in app.js but not in the route file)
I don't know how to send POST data with app.post
Any suggestion ?
app.post('/getAutoComplete', routes.read);
// assuming routes.read lookes something like this
routes.read = function read(req, res) {
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
};
Also check out https://github.com/mikeal/request It's the de-facto module for doing web requests in node.
routes.read is a function. You can call it with extra parameters, so for example
app.post('/getAutoComplete', function(req,res) {
var q = req.query.q; // or whatever data you need
routes.read(q, function(err, response) {
if (err) throw err;
return res.json(response);
});
});
Now make the routes.read function use the first parameter as the query and when it's gathered the response from the remote API, call the second parameter with any error as the first parameter and the response as the second one.
Update This answer has already been picked as an answer, but it'd be more helpful if I showed an example of routes.read, too:
routes.read = function(q, cb) {
// pretend we calculate the result
var result = q * 10;
if (result > 100) {
// call the callback with error set
return cb("q value too high");
}
// all is well, use setTimeout to demonstrate
// an asynchronous return
setTimeout(function() { cb(null, result) }, 2000);
};

Resources