Dialogflow Webhook (Webhook call failed. Error: 500 Internal Server Error) - javascript

I've followed this tutorial's code (https://dialogflow.com/docs/getting-started/basic-fulfillment-conversation) to return results of an API to dialog flow. However my webhook keeps failing. Can someone help me figure out why?
Here's one of the failed conversations:
Here's my code:
'use strict';
const http = require('http');
exports.Hadoop = (req, res) => {
// Get name node server from the request
let nameNodeServer = req.body.queryResult.parameters['nameNodeServer']; // nameNodeServer is a required param
// Call the Hadoop API
getNameNodeInfo(nameNodeServer).then(function(output) {
res.json({ 'fulfillmentText': output }); // Return the results to Dialogflow
}).catch(() => {
res.json({ 'fulfillmentText': 'getNameNodeInfo() Error'- });
});
};
function getNameNodeInfo (nameNodeServer) {
return new Promise((resolve, reject) => {
// Create url for the HTTP request to get the name node info
let url = 'http://' + nameNodeServer + '[rest of url]';
// Make the HTTP request to get the name node info
http.get(url, (res) => {
let body = ''; // var to store the response chunks
res.on('data', (chunk) => {body += chunk; });
res.on('end', () => {
// After all the data has been received, parse the JSON for desired data
let response = JSON.parse(body);
let beans = response['beans'][0];
// Create response
let output = `Percent Used: ${beans['PercentUsed']}`;
// Resolve the promise with the output text
console.log(output);
resolve(output);
});
res.on('error', (error) => {
console.log(`Error calling the Hadoop API: ${error}`);
reject();
});
});
});
}
I believe the getNameNodeInfo function and the retrieval of the name node server are correct, as they logged the correct output in debugging.
Diagnostic Info:

I contacted someone at Dialogflow and this was their response.
Thank you for providing all the information. I have observed in your
code that you have used http requests instead of https. The service
must use HTTPS and the URL must be publicly accessible in order for
the fulfillment to function. Dialogflow does not support self-signed
SSL certs. For information on SSL setup, please refer to this :
https://developers.google.com/web/fundamentals/security/encrypt-in-transit/enable-https

We've had a somewhat different, but related, issue:
Internal Server Error when running an agent.
“status”: {
“code”: 500,
“errorType”: “internal_server_error”,
“errorDetails”: “Internal Server Error”
},
This error was not caused by any changes we introduced. We are using that agent in a dev version of an app and one morning it stopped working.
We tested by creating a .zip and restoring into a new agent. The new agent would work properly, but we would continue to get the 500 error on the agent hooked into our dev app. We submitted a help request and overnight the error got resolved. We suspect that DialogFlow team had to manually reboot the server or something similar.

Related

Node Function Running Twice

I am using a simple JS script to query a Postgres DB. I simply want to write a simple query to the webpage, but every time I think I'm calling the function, it calls twice
// query the db
rate = () => pool
.query(rateQuery)
.then(res => {return res.rows[0]})
.catch(err => console.log('error: ', err.stack))
const app = http.createServer((request, response) => {
// set response header
response.writeHead(200, { 'Content-Type': 'text/html' });
// get result of promise
r = rate()
.then(res => response.write(JSON.stringify(res), () => {console.log("DONE"); response.end()}))
.catch(err => console.log('error: ', err.stack))
});
app.listen(3000);
When the page is refreshed, it prints DONE twice but I only want it once, any help is much appreciated - thanks.
If you add console.log(request.url) in your request handler, you will likely see that that the second request is when the browser asks your server for the /favicon.ico that represents the site. Browsers do this. When a user types in a URL for a site and hits enter, the browser requests that URL from the target site and then it also asks for /favicon.ico if there wasn't a previously cached icon already for that site.
In general, you should not have an http request handler like this that pays no attention to the request URL path because then you will process anything that the browser or a search crawler or anything sends you. Instead, you should look for a specific URL path and only do your work when it's the desired path and return a 404 response for all other paths.
I'd suggest you change your request handler to this:
const app = http.createServer((request, response) => {
// set response header
if (request.url === "/") {
// get result of promise
rate().then(res => {
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.write(JSON.stringify(res), () => {
response.end();
console.log("DONE");
});
}).catch(err => {
console.log('error: ', err.stack);
response.writeHead(500);
response.end();
});
} else {
response.writeHead(404, "unknown URL");
response.end();
}
});
Note: I change the content-type to text/plain. You had it as text/html, but you weren't sending html at all. You could perhaps make the content-type application/json, but in any case when you're sending JSON, it's not HTML.
This also incorporates cleaner error handling where all error paths send an error response.
P.S. Writing out this simple request handler using the plain http.createServer() request handler reminds me of how much simpler it is to use Express for request handler implementations. It handles so much of this for you while still giving you full control. It's lightweight and simpler.
FYI, here's the program written using Express:
const express = require('express');
const app = express();
app.get("/", (req, res) => {
rate().then(res => {
res.json(res);
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
});
// if we get here, then no other request handler handled the incoming request
// so we send back a 404
app.use((req, res) => {
res.sendStatus(404);
});
app.listen(3000);
There is one possibility. rate already is a function which you defined as
// query the db
rate = () => pool
.query(..........
Therefore, I don't think you would need parenthesis when you call it. Change from this
// get result of promise
r = rate()
.then .........
to this
// get result of promise
r = rate
.then .........

Avoid 'Remote request only' error Message when Node Server access domain

Using Node.js, I am trying to send a GET request to server and I've used the following code for that.
const https = require('https');
https.get('https://example-domain-name/', (resp) => {
let data = '';
// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log(data);
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
The problem is that, the server is responding statusCode 500 (Runtime error).
An application error occurred on the server. The current custom error
settings for this application prevent the details of the application
error from being viewed remotely (for security reasons). It could,
however, be viewed by browsers running on the local server machine.
But browser is displaying the page normally, but using node js request, i get the something following response data(text).
How to avoid this and normally request and response data like browser using node.js?
Please Help... StackOverFlow is only my basis of help now!!

Cant make http request with intent

So I'm currently trying to have an intent trigger an http request but keep getting errors.
When the intent triggers this code is executed
const https = require('https');
https.get('*************',
(resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
console.log(JSON.parse(data).explanation);
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
When running the intent I get Error: getaddrinfo ENOTFOUND back
My code works fine when I run it locally so the issue appears to be something not lining up properly with dialogflow
If anyone has any advice I would greatly appreciate it.
Thanks!
Dialogflow fulfillments are hosted as firebase cloud functions. Firebase free plan only allows Google service API. If you want to use an external API, you will have to upgrade your plan.
More information can be found here https://firebase.google.com/pricing/

Node gRPC: sending metadata from server to client without error

From the client side, it is easy to add metadata for the server:
const meta = new grpc.Metadata();
meta.add('xyz', 'okay');
stub.service.Rpc(request, meta, (err, response) => {
});
The above can be accessed on the server like this:
call.metadata.get('xyz');
Now, if we need to send metadata from the server to the client, we do this:
const err = { code, details };
const meta = new grpc.Metadata();
meta.add('...', '...');
callback(err, null, meta);
Note that we are passing error, and the actual response is null.
How do I pass a null error and a non-null response, along with metadata?
If I do the following, it does not seem to work as there is no way to access the metadata on the client without the error.
callback(null, r, meta);
// `r` is some response message
Does gRPC spec explicitly disallow sending metadata from server to client when there is no error?
Also, while we're at it, I'd like someone explain how do we send trailing vs initial metadata from server to client in Node.
Relevant links:
https://github.com/grpc/grpc-node
Can I send a custom Error message from server to client GRPC?
How to add metadata to nodejs grpc call
https://github.com/grpc/grpc/issues/9053
https://medium.com/compli-engineering/grpc-nodejs-using-jwt-authentication-b048fef6ecb2
ServerUnaryCall.sendMetadata(responseMetadata)
server:
const method = (call, cb) => {
// code
call.sendMetadata(metadata)
// code
}
client:
const call = client.method(params, cb)
call.on('metadata', (metadata) => {
// code
})
Looks like you can use such code:
client.someFunction().on('metadata', (meta) => { /* any code */ })
At least on v0.9.x you can see: https://github.com/grpc/grpc-node/blob/v1.9.x/packages/grpc-native-core/src/client.js#L562

NodeJS getting response from net socket write

I'm trying to get a response from specific requests via the write function.
I'm connected to an equipment via the net module (which is the only way to communicate with it). Currently, I have an .on('data',function) to listen to responses from the said equipment. I can send commands via the write functions to which I am expecting to receive a line of response. How can I go about doing this?
Current code:
server = net.Socket();
// connect to server
server.connect(<port>,<ip>,()=>{
console.log("Connected to server!");
});
// log data coming from the server
server.on("data",(data)=>{
console.log(''+data);
});
// send command to server
exports.write = function(command){
server.write(command+"\r\n");
};
This is a working code. Sending a command to the equipment via server.write returns a response which right now only appears in Terminal. I'd like to return that response right after the write request. Preferably within the exports.write function.
Add a callback argument to your exports.write function can solve your problem.
exports.write = function(command, callback){
server.write(command+"\r\n");
server.on('data', function (data) {
//this data is a Buffer object
callback(null, data)
});
server.on('error', function (error) {
callback(error, null)
});
};
call your write function
var server = require('./serverFilePath')
server.write('callback works', function(error, data){
console.log('Received: ' + data)
})

Categories

Resources