Invalid Lambda Response: Lambda response provided invalid slot names [slotId] - node.js

I get the error Invalid Lambda Response: Lambda response provided invalid slot names [slotId] when lambda sends response to lex using elicitSlot to get slot values for undefined slot.
I referred the lex blueprint code as following.
const handleOrder = async (intentRequest, callback) => {
const source = intentRequest.invocationSource
const id = intentRequest.currentIntent.slots.slotId
if (source === 'DialogCodeHook') {
// Perform basic validation on the supplied input slots. Use the elicitSlot dialog action to re-prompt for the first violation detected.
const slots = intentRequest.currentIntent.slots
const validationResult = validateOrderRequest(id)
if (!validationResult.isValid) {
//reset the slot value
slots[`${validationResult.violatedSlot}`] = null
callback(elicitSlot(intentRequest.sessionAttributes, intentRequest.currentIntent.name, slots, validationResult.violatedSlot, validationResult.message))
return;
}
const outputSessionAttributes = intentRequest.sessionAttributes || {}
callback(delegate(outputSessionAttributes, intentRequest.currentIntent.slots))
return;
}
...
}
function validateOrderRequest(id) {
if(!id){
return buildValidationResult(false, 'slotId', `Tell me the ID.`);
}
}
What could be giving the error?

You need not to use the statement
slots[${validationResult.violatedSlot}] = null;
It's not good practice to assign a slot value to null.
Remove this statement. I hope you won't get that error.

Related

Distributed Tracing with Service Bus Triggered Function

According to the docs around distributed tracing for Servicebus, the Diagnostic-Id property should be used to store the WC3 traceparent.
When an Azure Function is triggered via a service bus message, I would expect this value to be used to initialize the tracecontext (so AppInsight logs would get tagged with the appropriate operation_Id).
I've even tried to copy it over to the tracecontext and it doesn't seem to work.
Is it not possible to maintain distributed tracing with Service Bus in Azure functions?
Update
You can kinda of get this to work by implementing the wrapped app insights context, however, calls to context.log will still have the original traceparent reference :(
export default async function contextPropagatingHttpTrigger(context, req) {
// overwrite with the proper traceparent from the incoming SB message.
const sbTraceParent = context.bindingData.applicationProperties['diagnostic-Id'];
if (sbTraceParent) {
context.traceContext.traceparent = sbTraceParent;
}
const correlationContext = appInsights.startOperation(context, req) as CorrelationContext;
// Wrap the Function runtime with correlationContext
return appInsights.wrapWithCorrelationContext(async () => {
const startTime = Date.now(); // Start trackRequest timer
try {
// operation_Id matches SB 'diagnostic-Id'
appInsights.defaultClient.trackTrace({
message: 'Correct Trace Context',
});
// operation_Id is the original function traceparent
context.log('Incorrect Trace Context');
return await trigger(context, req);
} catch (e) {
context.log.error(e);
throw e;
} finally {
// Track Request on completion
appInsights.defaultClient.flush();
}
}, correlationContext)();
}

nodejs condense a validation of json body request against regex

Is there a condensed way to do this validation on nodejs
//inbound express request
{ "myVal":"abcdefghij" }
/* first test if value exists,
then if it fails a regex return an error & exit function
if pass then continue
*/
// ... logic to get express.post(...=> {
if (( req.body.myVal == null ){
// no value, send error response and exit function
}else{
const inVar = req.body.myVal;
if ( inVar ){
const regex = /^([a-j0-9]){1,11}$/;
if(regex.test(inVar ) == false){
res.send({ error: "failed regex" });
res.end();
return;
}
... else continue
Here are a few options:
Use express-validator or a similar package to validate your endpoint params and/or body in the endpoint configuration. This nicely separates validation from the logic of the endpoint and is extensible to your other endpoints without having to maintain code in each one.
Check out the package here:
Express-validator
Specifically, what you might want is their custom validator:
Express-validator's custom validation docs
Example usage:
const { body } = require('express-validator');
const MY_REGEX = /^([a-j0-9]){1,11}$/;
app.post('/my-endpoint',
body('myVar').custom(value => {
if(!MY_REGEX.test(value)) Promise.reject("Error: invalid value for 'myVar.'")
}),
(req, res) => {
// Business logic only, no validation
},
);
You could even take the function that's inside .custom(), and put it in another file, import it here, and reuse it elsewhere.
If you want to do the validation in the handler, there are a few ways to make your code more brief/safe/nice.
Set your regexp variable in a different file or as a constant at the top of the file (descriptively) or in a different constants/utils file.
"Error gate" by returning after you find an error. Avoid nested if/else.
Is the error the same for missing value and incorrect value? If so, your regexp will error appropriately for undefined, empty string, and null anyway. consider combining them in the same if statement.
Example:
// imports
// ...
const MY_DESCRIPTIVE_REGEX_NAME = /^([a-j0-9]){1,11}$/;
//...
(req, res) => {
if(!MY_DESCRIPTIVE_REGEX_NAME.test(req.body.myVal) {
res.status(400);
return res.send({ error: "MyVal must be between 1 and 11 characters and contain only numbers and letters between 'a' and 'j'."});
}
// rest of logic, not in an if statement
}

calling a web service and get the response to a variable(String) using nodejs. and return that string in ibm cloud functions

I create an ibm cloud function. I am using nodejs as my coding language. once i entered the following few lines in the editor and invoke it.
function main() {
return { message:'response from server' };
}
Then i got the 'response from server' as the result.(successful)
As like that I want to call an external web service and get that response(String) instead of this hard-coded response. So I used the below lines for that
const request = require('request-promise');
function web(){
return request("https://58a78829.ngrok.io/webhook/testRequest")
.then(function(response){
return Promise.resolve(JSON.parse(response));
});
}
function main(){
var y;
web().then(function(result){
y=result;
console.log(y);
});
return { message: y };
}
once I invoke the above code I get nothing as result or log. no value is assign to variable y.
I am not sure whether we can assign the value which return from a method to a variable in nodejs8.
Could any one please help me to solve this.
You can simply use async await feature of javascript for that. After writing the same code with async await your code will look something like below.
const request = require('request-promise');
async function web(){
const res = await request("https://58a78829.ngrok.io/webhook/testRequest");
return res;
}
async function main(){
const x = await web();
console.log('x: ', x);
return { message: x };
}

Firebase functions returns RangeError at Function.MapValues

I've run into an issue with a firebase function, written in TypeScript for the Node.js environment. I have a function with https-endpoint where the client can send data that needs to be stored in the database. In order to know which objects already has been added to the database, it first reads a path ("lookup") that has a simplified registry of the object (lookup/:objectId/true). Then it makes the values that should be updated at the actual object path and updates these in the database.
The function is as follows:
export const scrapeAssignments = functions.https.onCall((data, context) => {
const htmlString = data.htmlString
// const htmlString = fs.readFileSync(testPath.join(__dirname, "./assignmentListExample.html"), { encoding: 'utf8' })
if (!(typeof htmlString === 'string') || htmlString.length === 0) {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with one argument "htmlString"');
}
const userId = getUserIdFromCallableContext(context)
console.log("userId", userId)
let newAssignments: ScrapedAssignment[] = []
try {
newAssignments = parseAssignment(htmlString)
} catch (e) {
const error = <Error>e
throw new functions.https.HttpsError('not-found', 'parsing error: ' + error.message)
}
return admin.database().ref("lookup").child(userId).child("assignments")
.once("value", lookupSnapshot => {
const oldAssignmentsLookup = lookupSnapshot.val() || {}
const newAssignmentsLookup = makeLookup(newAssignments)
// 1. Create update values for scraped assignment data
let scrapedAssignmentUpdateValues = newAssignments.reduce((prev, current) => {
const prefixed = prefixObject(current.id + "/", current)
return { ...prev, ...prefixed }
}, {})
// 2. Use the diff from the two lookups to find old assignments to delete
const removeAssignmentsValues = {}
Object.keys(oldAssignmentsLookup).forEach(assignmentId => {
if (isUndefined(newAssignmentsLookup[assignmentId]))
removeAssignmentsValues[assignmentId] = null
})
// 3. Add other user values to newly found assignments
Object.keys(newAssignmentsLookup).forEach(assignmentId => {
if (isUndefined(oldAssignmentsLookup[assignmentId])) {
const doneKey = assignmentId + "/done"
scrapedAssignmentUpdateValues[doneKey] = false
}
})
const combinedValues = { ...scrapedAssignmentUpdateValues, ...removeAssignmentsValues }
return admin.database().ref("userAssignments").child(userId).update(combinedValues)
}).catch(reason => {
throw new functions.https.HttpsError('internal', 'Database reason: ' + reason)
})
})
I see that the data is written to the right place and everything seems to go as expected, except that when I call the function from an iOS app, It returns an "Internal"-error
When I check the function logs in the cloud console, I see the following error:
assignment-scrapeAssignments uolk47opctna Unhandled error RangeError:
Maximum call stack size exceeded at Function.mapValues
(/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13395:23)
at encode
(/user_code/node_modules/firebase-functions/lib/providers/https.js:204:18)
at
/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13400:38
at
/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15
at baseForOwn
(/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24)
at Function.mapValues
(/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399:7)
at encode
(/user_code/node_modules/firebase-functions/lib/providers/https.js:204:18)
at
/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13400:38
at
/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15
at baseForOwn
(/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24)
at Function.mapValues
(/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399:7)
All I can read out of this, is that it's an "RangeError: Maximum call stack size exceeded"-error, and something happens at Function.mapValues. As I can read from this SO question it seems to be an issue with a reading and writing to the same location at the same time. But I'm quite sure that I'm not doing that here.. Plus everything seems behave like it should, except for the actual error.
When combinedValues is updated, it is an object with ~300 key/value pairs, is that a problem?
Looks like your function run out of memory, every cloud function has allocated memory to its execution.
You can try to increase the stack size from its default value (256MB) up to 2GB by going to:
Functions-> Dashboard, then go to your problematic function and click on the right menu "Detailed usage stats":
then on your function details in google cloud dashboard click edit:
then increase the value of "memory allocated" to 2GB (or lower sufficient value):
note: you should keep in mind that when your data growth you may exceed the highest limit so consider this when querying in the cloud functions

Custom exception name instead of UserLambdaValidationException

I use the Pre sign-up trigger of Cognito to validate the user registration. If some validation fails the function responses with a custom error. The client only receive the UserLambdaValidationException as ErrorCode.
Is there a way to receive the custom error name instead?
Current using sample:
exports.handler = function(event, context, callback) {
function AccountAlreadyExistsError(message) {
this.name = "AccountAlreadyExistsError";
this.message = message;
}
AccountAlreadyExistsError.prototype = new Error();
const error = new AccountAlreadyExistsError("Account is in use!");
callback(error);
};
I want to get AccountAlreadyExistsError in our client instead of UserLambdaValidationException.
You can customise exception headers only if it is a Lambda Proxy, with the API Gateway (x-amzn-errortype header), in any other case you need to parse the exception message to get your custom exception, here is an example how I manage exceptions for Cognito lambda triggers, it's just to show you the idea:
/*
Lambda Code, could be in a Lambda layer
*/
const EXCEPTION_TYPE_DELIMITER = "etype"
const EXCEPTION_MESSAGE_DELIMITER = "emsg";
const beTagged = (tag, txt) => {
return "<" + tag + ">" + txt + "</" + tag + ">";
};
class UserNotAllowedException extends Error {
constructor (message) {
super(beTagged(EXCEPTION_MESSAGE_DELIMITER, message))
Error.captureStackTrace(this, this.constructor);
this.name = beTagged(EXCEPTION_TYPE_DELIMITER, this.constructor.name);
}
}
exports.handler = async (event, context, callback) => {
// Your logic, etc..
throw new UserNotAllowedException("You are blocked :(");
}
Here is the parser
/*
Client Code
*/
const EXCEPTION_TYPE_DELIMITER_REGEX = /<etype>(.*?)<\/etype>/g;
const EXCEPTION_TYPE_UNTAG_REGEX = /<\/?etype>/g;
const EXCEPTION_MESSAGE_DELIMITER_REGEX = /<emsg>(.*?)<\/emsg>/g;
const EXCEPTION_MESSAGE_UNTAG_REGEX = /<\/?emsg>/g;
const untag = (txt, delimiterRegex, untagRegex) => {
return txt.match(delimiterRegex).map(etype => {
return etype.replace(untagRegex,"");
})[0];
};
const resolveException = (exceptionMessage) => {
const exceptionType = untag(exceptionMessage, EXCEPTION_TYPE_DELIMITER_REGEX, EXCEPTION_TYPE_UNTAG_REGEX);
const exceptionMessage = untag(exceptionMessage, EXCEPTION_MESSAGE_DELIMITER_REGEX, EXCEPTION_MESSAGE_UNTAG_REGEX);
// Your logic to determine what exception is the exceptionType
return new YourResolvedException(exceptionMessage);
};
try {
// This guy should throw the exception
return await Auth.signUp(params);
} catch (e) {
// Expected message from Cognito Lambda Trigger
// PreSignUp failed with error <etype>UserNotAllowedException</etype>: <emsg>You are blocked :(</emsg>.
// For example, here your custom exception resolver
throw resolveException(e.message);
}
It can be done in a thousand ways, but the best thing for us would be if the AWS services were able to fully customise the exceptions without so much hassle.
Regards!
I tried it on my end and was able to get the error message in the client. Tested it using AWS CLI, Nodejs & the built-in Cognito UI. I returned the error using:
var error = new Error('something went wrong..!');
callback(error,event);
I got the error UserLambdaValidationException: PreSignUp failed with error something went wrong..! in all my clients. Even callback(error) worked.

Resources