I am using the dialogflow agent and trying to send a response to the user.
Here is my code:
app.intent('Answer6', (conv) => {
const ans = conv.parameters.any;
senddata[8] = qstion[8] + ans;
conv.close('Thank you');
});
After this intent, I am getting this error:
Error: No response has been set.
Is this being used in an async call that was not returned as a promise to the intent handler? at DialogflowConversation.response
If you're not using async functions, and it doesn't look like you are, this is usually an indication that your function crashed while running. You may wish to check the logs of where the function is running (Cloud Functions, for example) and see what other errors are being generated.
Related
Is there possible way to handle error that will return right back after error is triggered?
if(command === 'test') {
message.author.send('Dm Test').catch(error => {
message.reply('I failed to send you a private message!')
return;
})
//some code below, should not trigger after sending message error.
The problem is that .catch will respond as last, how to handle this error and immediately return instead of running also code below? I tried to use try { but that didn't work.
message.author.send('š')
.catch(() => message.reply("Can't send DM to your user!"));
Would like to know if there is another way to handle error. Any help will be much appreciated.
The reason why .catch() executes after the rest of your code is because .send() is asynchronous and returns a Promise. Think of it this way: each time you send a message, discord.js has to send an HTTP request to the Discord API, wait for a response, and then give you the data from the response. That process is not instantaneous and takes some time, which is why using the Promise structure is very useful.
As for the specific problem, you simply want to await the response of your .catch(). This can be done by making the function you are running this code in async. Here is an example:
client.on("messageCreate", async (message) => {
let response = await message.author.send('š').catch(() => {
message.reply("Can't send DM to your user!"));
return false;
});
// (If error occurred, 'response' will be false)
if (!response) return; // Return if the error occurred
// ... Code for if error did not occur
// (If no error occurred, 'response' will contain sent message)
});
The await keyword will wait until the asynchronous line you are executing has been fulfilled (i.e. until the return value has been obtained or an error has been caught) before continuing on with your code. Note the use of the async keyword. You can only use await within functions marked async.
If you place a return before sending the error message, JavaScript will read that as you're returning the message so if you do the following:
message.author.send('š')
.catch(() => return message.reply("Can't send DM to your user!"));
you'll have the error message be the final command run and nothing else will follow.
You can use try inside of if & else statement to know if you can dm the person or not.
if(command === 'test') {
try {
message.author.send("Something right here")
} catch {
message.channel.send("I can't dm this person.")
} else {
//something exploration code here
}
}
I'm trying to code a discord bot that server mutes people when i do ".mute #person"
What's wrong with my code?
bot.on('message', msg=>{
let person = message.guild.member(message.mentions.users.first() || message.guild.members.get(args[1]))
if(msg.content === ".mute"){
person.setDeaf
}
})
It says "message not defined"
bot.on('message', msg => {...} waits for the event message then passes that information as the variable msg for the function provided.
Inside your function, you refer to message.guild.member but message is undefined (you passed your event information as msg, not message). Change your function parameter to message, so it looks like this:
bot.on('message', message => {...})
That would fix the error you're getting, but I'm not sure that function will actually server mute a user. I think what you want is:
client.on('message', async message => {
if (message.content.startsWith(".mute")) {
let person = message.guild.member(message.mentions.users.first());
await person.edit({mute: true});
}
});
Notice I use message as the parameter for the function, but I put async in front of it because I'm going to be using an asynchronous function. .edit() takes a dictionary of data, see the linked documentation. It is awaited because it is done asynchronously: you call it, then you wait for a response from the server before continuing (to make sure everything happened as expected).
Tested myself, works like a charm.
I am using the excellent stripe documentation to build a webhook to respond to a stripe successful payment. The code works fine however as soon as I introduced async-await, I get a 500 Internal server error.
I am testing the firebase onRequest webhook function through the send test webhook on the stripe website.
My code lives here
What am I missing?
firebase function with async-await does not work:
exports.stripeEvents = functions.https.onRequest(async (request, response) =>
{
try
{
let stripesignature = request.headers['stripe-signature'] as string;
let stripeevent:Stripe.Event= stripe.webhooks.constructEvent(request.rawBody.toString('utf8'), stripesignature, config.stripewebhooksecretkey);
if(stripeevent.type === 'payment_intent.succeeded')
{
let payment_intent1 = stripeevent.data.object as Stripe.PaymentIntent;
let datafirstelement=null;
if(payment_intent1?.charges?.data && payment_intent1?.charges?.data.length>0)
{
datafirstelement=payment_intent1?.charges?.data[0];
}
let userid='someuserid';
let documentreference=config.db.collection('users').doc(userid);
await documentreference.update({payments: admin.firestore.FieldValue.arrayUnion(datafirstelement)});
response.status(200).send({'result':true});
}
}
catch(error)
{
//log error into sentry
throw error;
}
});
firebase function without async-await, works:
exports.stripeEvents = functions.https.onRequest((request, response) =>
{
try
{
let stripesignature = request.headers['stripe-signature'] as string;
let stripeevent:Stripe.Event= stripe.webhooks.constructEvent(request.rawBody.toString('utf8'), stripesignature, config.stripewebhooksecretkey);
if(stripeevent.type === 'payment_intent.succeeded')
{
let payment_intent1 = stripeevent.data.object as Stripe.PaymentIntent;
let datafirstelement=null;
if(payment_intent1?.charges?.data && payment_intent1?.charges?.data.length>0)
{
datafirstelement=payment_intent1?.charges?.data[0];
}
let userid='someuserid';
let documentreference=config.db.collection('users').doc(userid);
//await documentreference.update({payments: //admin.firestore.FieldValue.arrayUnion(datafirstelement)});
response.status(200).send({'result':true});
}
}
catch(error)
{
//log error into sentry
throw error;
}
});
update 1: I am testing the firebase onRequest webhook function through the send test webhook on the stripe website.
successful stripe payments when not using async-await, internal server error when using async-await:
webhook success logs when not using async-await(and no logs when using async-await):
update 2: firebase function log:
stripeEvents
Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.
at Object.validateResourcePath (/workspace/node_modules/#google-cloud/firestore/build/src/path.js:403:15)
at CollectionReference.doc (/workspace/node_modules/#google-cloud/firestore/build/src/reference.js:1988:20)
at exports.stripeEvents.functions.https.onRequest (/workspace/lib/index.js:115:85)
at cloudFunction (/workspace/node_modules/firebase-functions/lib/providers/https.js:51:16)
at process.nextTick (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:99:17)
at process._tickCallback (internal/process/next_tick.js:61:11)
update 3: firebase function log:
I changed line await documentreference.update({payments: //admin.firestore.FieldValue.arrayUnion(datafirstelement)}); to await documentreference.set({payments: admin.firestore.FieldValue.arrayUnion(datafirstelement)}, {merge:true}); and the application still throws the following errors. The code lives here.
12:02:30.464 AM
stripeEvents
Function execution started
12:02:54.174 AM
stripeEvents
Function execution started
12:02:54.901 AM
stripeEvents
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
12:02:54.905 AM
stripeEvents
Function execution took 732 ms, finished with status: 'crash'
12:03:30.467 AM
stripeEvents
Function execution took 60004 ms, finished with status: 'timeout'
From the comments above and from the error you get (Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.), it seems that the value you pass to the doc() method while testing your Cloud Function is an empty string.
You need to mock data in your test in order to pass a correct value to the doc() method.
Note that Iām not sure that testing it "from the web application" (as you mention in the comments above) will change something, since the stripe Webhook has nothing to do with your web application (the Stripe backend calls your backend, i.e. your Cloud Function). You may send the userId as payment metadata to Stripe and (1) add it as query string parameter to the URL called by the webhook and (2) parse and use this value in your Cloud Function.
Note also that the difference between your "async version" that does not work and you "non async version" that works is not about async/await but is just that you comment out the line that generates the error.
I am trying to create intent in which when the user sends a parameter, then it should be checked in the database that is already there or not. If it already exists user gets a response A and if not it is added to the database, & the user gets response B. I am using Axios to make the API calls. But the code is not working.
I am getting a following errors in the console.
TypeError: Cannot set property 'response' of undefined
at axios.get.then.response (/srv/index.js:33:18)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)"
Show matching entries
Hide matching entries
Add field to summary line
I am not a professional, I am doing all this coding by learning from online tutorials and youtube videos Please help.
function idHandler(agent) {
const idcard = agent.parameters.idcard;
const idvalue = ' ';
const idname= ' ';
axios.get('API' + idcard)
.then(response => {
this.response = response.data;
idvalue = this.response[0].IDcard;
idname = this.response[0].Name;
});
if (idcard === idvalue) {
const ans = 'Name of ' + idname + ' is already present in the List';
agent.add(ans);
} else {
const data = [{
idcard: idcard
}];
axios.post('API', data);
}
}
You have a few issues with both how to code for Dialogflow, and how to express some of the syntax correctly. Some of that is because it looks like you're mixing code that expects Promises with code that doesn't.
The axios library is meant to work with Promises - the get and post methods both return Promises. So you can either work with them by using an await method, or by using the .then() method that the returned Promise has. You may want to look up details of both.
Additionally, Dialogflow requires that you either return the Promise, or that your handler be an async function (which will return a Promise for you).
If you're using the .then() approach, however, then everything you do that relies on the call to axios must be done inside the .then() block and you must return that Promise. If you use await, then your function must be declared as an async function. (You can probably mix the two - but don't.)
So that part of your code might look something like:
return axios.get( url )
.then( response => {
// Do EVERYTHING in here
});
And inside the then() code block is where you would extract the values you want, call agent.add() with the message, and possibly make the API call to add data.
While this didn't get flagged as an error, you are trying to assign a value to a const after it is initially set. This is an error. Those should probably be declared using let instead.
Your error looks like it is saying that this is undefined. Which seems... odd. But also not really an issue since you probably don't need to be using this for most of what you're trying to do. If you scope the variables with let, then they should be available for the life of the function.
I was trying to get my hands dirty on advanced NodeJS concepts by Stephen Grinder.
Trying to teach the mere basics of redis, Stephen did something like this
app.get('/api/blogs', requireLogin, async (req, res) => {
//This time we are setting
const redis = require('redis')
const redisURL = 'redis://127.0.0.1:6379';
const client = redis.createClient(redisURL);
const util = require('util')
client.get = util.promisify(client.get)
//We are checking if we have ever fetched any blogs related to the user with req.user.id
const cachedBlog = await client.get(req.user.id)
//if we have stored list of blogs, we will return those
if (cachedBlog) {
console.log(cachedBlog)
console.log("Serving from Cache")
return res.send(JSON.parse(cachedBlogs))
} //this is JSONIFIED as well so we need to convert it into list of arrays
console.log("serving from Mongoose")
//if no cache exsist
const blogs = await Blog.find({_user: req.user.id})
//blogs here is an object so we would need to stringfy it
res.send(blogs);
client.set(req.user.id, JSON.stringify(blogs))
})
And it works without any error but in last two lines, if we change the order
client.set(req.user.id, JSON.stringify(blogs))
res.send(blogs);
it does not display my blog.
Since inside the API, I am considering both of them to run asynchronously, I thought order won't matter.
Can anyone tell me what am I missing or unable to comprehend?
Since OP asks to understand the difference, not fix the code:
express runs the request handler function and catches synchronous errors (they become http500 errors). It doesn't do anything with the promise returned from the async function and doesn't use await internally, so you don't get error handling for async functions for free. All asynchronous errors need to be caught inside and passed to the next callback or handled in your code by sending an appropriate status code and error body.
When an error occurs, JS stops and doesn't execute any more lines in the function. So if an error is thrown from client.set placed before res.send, the line with send won't run and no response is sent. The browser should continue waiting for the response until timeout.
The other way around - you send response before the error, so you get the page, but the response doesn't end (I'd assume the connection remains open as if the backend was going to send more) but ever since early versions of Firefox browsers start rendering HTML as it's downloaded, so you see a page even though the browser is still waiting for the response to finish.
The order of these two lines doesn't matter but that res.send isn't called in case client.set goes first means that there's an error. If an error occurs in async function, this may result in UnhandledPromiseRejectionWarning warning that will be visible in console.
There are several problems with this snippet.
That the error occurs even when though client.set is asynchronous suggests that client.set causes synchronous error which wasn't caught.
client.set wasn't promisified but it should for correct control flow. That it wasn't provided with callback argument could be a reason why it caused an error.
As explained in this answer, Express doesn't support promises, all rejections should be explicitly handled for proper error handling.
All common code like require goes outside middleware function. It should be:
const redis = require('redis')
const redisURL = 'redis://127.0.0.1:6379';
const client = redis.createClient(redisURL);
const util = require('util')
client.get = util.promisify(client.get)
client.set = util.promisify(client.set)
app.get('/api/blogs', requireLogin, async (req, res, next) => {
try {
const cachedBlog = await client.get(req.user.id)
if (cachedBlog) {
return res.send(JSON.parse(cachedBlogs))
}
const blogs = await Blog.find({_user: req.user.id});
await client.set(req.user.id, JSON.stringify(blogs));
res.send(blogs);
} catch (err) {
next(err);
}
})
Most popular libraries have promise counterparts that allow to skip boilerplate promisification code, this applies to redis as well.
The two task will runs asynchronously but the order of execution matters.
client.set(req.user.id, JSON.stringify(blogs)) execution starts first, but as you are not using await, the promise will not be resolved but execution has already started.
After that res.send() will execute.
You are not getting the response implies that there is some error in the execution of client.set(req.user.id, JSON.stringify(blogs)).
Use Try catch block to trace this error (as mentioned in other answers).
You can also add these lines in your code to catch other "unhandledRejection" or "uncaughtException" error (if any).
process.on('unhandledRejection', (err) => {
logger.error('An unhandledRejection error occurred!');
logger.error(err.stack)
});
process.on('uncaughtException', function (err) {
logger.error('An uncaught error occurred!');
logger.error(err.stack);
});