Sending node.js response and processing in client - node.js

I have a server in node.js which handles registration from users.
When someone attempts to register I first check if the introduced email already exists in my database, and if not I send a response back saying that that email has already been used.
The problem is that when I send a response with response.write() when the browser receives the response it replaces all the webpage by the response text, and what I want is to use that response to display a message next to the form in the registration page.
I also want to get the response with a Dart event listener so that the client knows that the email is in use and can display the message. My code for making the HTTP request with Dart is the following:
signupSubmit.onClick.listen((e) {
var req = new HttpRequest();
req.onReadyStateChange.listen((e) {
if (req.readyState == HttpRequest.DONE) {
print('Data submitted!');
}
});
req.open('POST', signupForm.action);
req.send(JSON.encode(serializeForm(signupForm)));
});
serializeForm(FormElement form) {
var data = {};
form.querySelectorAll('input,select').forEach((Element el) {
if (el is InputElement)
data[el.name] = el.value;
});
return data;
}
So how can I send a response that I can process in the client?
And how can I get the server response with Dart?

The signupSubmit click seems to submit its <form>. You can block the default form submission with :
signupForm.onSubmit.listen((e) => e.preventDefault());

Related

Indicating a WhatsApp message is received, via the Twilio API, in NodeJS?

We are creating a service that will receive WhatsApp messages via the Twilio service. This works, but our issue is that we can't work out how to tell the sender that our server has 'read' the message. The messages always appear as being 'delivered' and never 'read', even after responding to the message. We have looked in the documentation, but can't seem to see how to do this.
Our server is written in NodeJS and is using Express for HTTP side.
Below is an equivalent of the code we are using (not a running example):
import { twiml } from 'twilio';
const { MessagingResponse } = twiml;
async receiveMessage(req: Request, res: Response, next: NextFunction) {
const message = req.body;
// Send back an empty response, we will process asynchronously
const immediateResponse = new MessagingResponse();
res.setHeader('content-type', 'text/xml');
res.send(immediateResponse.toString());
// TODO indicate message as read
// Do what ever logic is needed for given message
const replyMessage = await processMessage(message);
const messageToTwilio = {
body: replyMessage,
from: message.To,
to: message.From
};
const twilioResponse = await this.client.messages.create(messageToTwilio);
// Record value of twilioResponse in DB
}
Can anyone suggest what in the API I should be using for this?
I contacted Twilio on this issue and it turns out this is not currently possible. While they consider this a useful functionality, it is not currently a priority for implementation.
Note, It is possible to get the delivery status of outgoing messages, via the status webhook, but it is not possible to indicate to the remote party that the incoming message was 'read'.

store unique usersId across conversations with Dialogflow (userStorage ERROR Can't set headers after sent to user)

I am trying to make a Google Home app and I am using webhooks with express.js running on a local server as fulfilment. I would like to use the "request.body.originalDetectIntentRequest.payload.user.userStorage" parameter from the request to identify a user when the webhook sends a post request to my server. The userId given with this request is equal to a log-filename that I store locally for each user where I keep track of different things per user.
I got the idea of handling things like this from an earlier post here on stack overflow. In the answer given by Prisoner, he talks about the importance of the response that you have to send back. So far so good, I tried to implement this in my code by sending a response once the new userId is made but I keep getting the same error :
(node:21236) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:518:11)
So it probably has to do with the fact that I have a line agent.handleRequest(intentMap); at the end of my code which will handle the request and send a response back to the user itself.
How do I solve this? I already tried to find a solution for this problem but the after trying different things, there is only one thing I can think of which would be to expand the response before sending it with the payload.google.userStorage variable even though I have tried response.write but that was giving me the same error.
My code:
app.post('/', express.json(), (request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
let userStorage = request.body.originalDetectIntentRequest.payload.user.userStorage || JSON.stringify({});
let userId;
console.log("userStorage", userStorage);
userStorage = JSON.parse(userStorage);
console.log("userStorage_after_parsing", userStorage);
if (userStorage.hasOwnProperty('userId')) {
userId = userStorage.userId;
console.log('user was already defined:' + userId);
} else {
let uuid = require('uuid/v4');
checkNewUser = true;
userId = uuid();
userStorage.userId = userId
console.log(userId);
response.send({
'payload': {
'google': {
'userStorage': JSON.stringify(userStorage)
}
}
}
);
//rest of the code
agent.handle(intentMap)
UPDATED QUESTION:
After prisoner's answer, I decided to include the code of the handleWelcome intent where I would like to paste the code into to extend the response with the the userStorage variable:
function handleWelcome(agent) {
//code to add userStorage to the response?
if (checkIfUserVerified() === true) {
agent.add('Hi.');
//updateLog('User just said hi.');
let userObj = readJsonSync(userId + '.json');
userObj.logs.push('User just started talking to this chatbot ' + getCurrentDateTime());
fs.writeFileSync(userId + '.json', JSON.stringify(userObj));
}
else {
close('Please make sure you are a verified user before using this version of SMART4MD. To do so, read the SMART4MD Voice assistant manual.');
agent.setFollowupEvent('GOODBYE');
}
}
Note the comment in the answer you cite where it says
// Make sure you include the userStorage as part of the response
"part of" the response - not the response itself. In your code, you're sending back the JSON to sent the user storage before your Intent Handler is called. Once something is sent, the connection is closed, so nothing further can be sent - including the reply you want. Which is why you get the error.
You don't show any of your Intent Handler functions, so it is difficult to give you an exact answer, but the general solution would be to set the userid in userStorage as part of a function that each handler calls.

How to open web brower by using AWS post lambda

I have written the piece of code below:
static async postSearchResult(httpContext: HttpContext, injector: Injector) {
const log = injector.get(Log);
const service = injector.get(Service);
try {
let result = await service.redirectToUI(JSON.parse(httpContext.getRequestBody()));
httpContext.ok(result, 200, {'Content-Type': 'application/json'});
} catch (e) {
httpContext.fail(e, 500);
}
}
protected redirectToUI(response: any) {
// If any post api call happened then it should open web browser and pass some field as query parameter
window.open("https://www.google.com?abc=response.abc");
return response ? response : "failed";
}
Here I am getting the following error :
Execution failed ReferenceError: Window is not defined
What am I doing wrong?
What you are trying to accomplish doesn't make much of a sense. Lambda is a back-end service. To open new browser window, you need to use front-end JavaScript, not back-end Node (on the back-end, you have no access to the front-end window object).
If you want to open a new browser window as a reaction to some back-end response, then you can send some indicator in the HTTP response (i.e shouldOpenNewWindow: true as a part of the response object), parse that response on the front-end and it the indicator is present, then you can issue window.open command. But it has to be done on front-end.

node express back to back same POST request

I am using node express API in my application, I am facing below issue for API.
I have API which accept header parameter test and values like 1 to 5. Response is depends on header value, different response for different header parameter value.
Problem : If I am using with Single client (say POSTMAN) it is working fine, but if I am using two POSTMAN with different header parameter say in one window test=2 and
another window test=5 and if I send both request one after another then on both POSTMAN window I am getting response whichever I am sending first.
For response after some backend work I am sending response.
Below code I am using..
router.post('/:sample/:temp', function(req, res){
....
if(obj.st == "acknowledged"){
res.write(message);
}else if (obj.st == "completed") {
res.write(message);
res.end();
}
}
Update 1 :
After getting request I am waiting for response from MQTT topic where first I am getting acknowledged which I am storing like res.write(message) and after some time (may be after 1 second) on same topic I am getting completed after that I am sending response to user(API response).
router.post('/:sample/:temp', function(req, res){
....
client.on('message', function(topic, message){
var obj = JSON.parse(message);
if(obj.st == "acknowledged"){
res.write(message);
res.write("\n\n");
}else if (obj.st == "completed") {
res.write(message);
res.end();
client.end();
}
});
}
Update 2 :
Using below URL for POST request
http://localhost:8080/myapp/<path_param1>/<path_param2>

How to cancel previous ES request before making a new one

I am using NodeJS with https://www.npmjs.com/package/elasticsearch package
Use Case is like this: When a link is clicked on the page, I will make a request to NodeJS Server which will in turn use the ES node package to fetch the data from ES Server and sends the data back to the client.
The issue is, when two requests are made in quick session(two links clicked in a short span), the Response of first request and then the Response of second request is reaching the client. The UI depends on this response, and i would like to directly show only the second request's response.
So, the question is, Is there any way to cancel out the previous request made to ES Server before starting a new one ?
Code:
ES Client:
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
host: 'HostName',
log: 'trace'
});
Route:
app.get('/data/:reportName', dataController.getReportData);
DataController:
function getReportData(req, res) {
query = getQueryForReport(report)
client.search(query)
.then(function(response) {
res.json(parseResponse(response)
})
}
So, the same API /data/reportName is called twice in succession with different reportNames. I would like to send only the second report Data back and cancel our the first request.
If you're only concerned about the UX, rather than stressing your ES, than aborting the ajax request is what you want.
Since you didn't post your client side code, I'll give you a generic example:
var xhr = $.ajax({
type: "GET",
url: "searching_route",
data: "name=John&location=Boston",
success: function(msg){
alert( "Data Saved: " + msg );
}
});
//kill the request
xhr.abort()
Remember that aborting the request may not prevent the elasticsearch query from being processed, but will prevent the client from receiving the data.

Resources