How do you pass query parameters to a GET endpoint - amazon-web-services

I have a simple Lambda function that for now returns the event. So when I test with this, I return event.body.url and event.body.wepbSupport. That works in the AWS Lambda test environment.
TEST
{
"body": {
"url": "https://someURL.com",
"webpSupport": true
}
}
RESPONSE
Test Event Name
test
Response
{
"url": "https://someURL.com",
"webpSupport": true
}
I have no idea how to pass this query string to the staging API Gateway staging URL. All the documentation from AWS shows an old interface that they've changed. I see add URL Query String Parameters in these instructions but don't see that anywhere in the new interface.
Cloudwatch logs show me this:
{
"errorType": "TypeError",
"errorMessage": "The \"url\" argument must be of type string. Received undefined",
"code": "ERR_INVALID_ARG_TYPE",
"stack": [
"TypeError [ERR_INVALID_ARG_TYPE]: The \"url\" argument must be of type string. Received undefined",
" at validateString (internal/validators.js:124:11)",
" at Url.parse (url.js:170:3)",
" at Object.urlParse [as parse] (url.js:157:13)",
" at dispatchHttpRequest (/var/task/node_modules/axios/lib/adapters/http.js:91:22)",
" at new Promise (<anonymous>)",
" at httpAdapter (/var/task/node_modules/axios/lib/adapters/http.js:46:10)",
" at dispatchRequest (/var/task/node_modules/axios/lib/core/dispatchRequest.js:52:10)",
" at async Promise.all (index 0)",
" at async Runtime.exports.handler (/var/task/index.js:4:28)"
]
}

After examining the event object I see that all GET query parameters are passed in event.queryStringParameters. Leaving this on the site in case anyone else stumbles across this question.

Related

I am receiving a reference error in AWS lambda

I am trying to learn to make a web app and I am trying to follow the tutorial provided by AWS but I am coming in to this issue in making a Lambda function.
{
"errorType": "ReferenceError",
"errorMessage": "exports is not defined in ES module scope",
"trace": [
"ReferenceError: exports is not defined in ES module scope",
" at file:///var/task/index.mjs:3:1",
" at ModuleJob.run (node:internal/modules/esm/module_job:193:25)",
" at async Promise.all (index 0)",
" at async ESMLoader.import (node:internal/modules/esm/loader:530:24)",
" at async _tryAwaitImport (file:///var/runtime/index.mjs:921:16)",
" at async _tryRequire (file:///var/runtime/index.mjs:970:86)",
" at async _loadUserApp (file:///var/runtime/index.mjs:994:16)",
" at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)",
" at async start (file:///var/runtime/index.mjs:1200:23)",
" at async file:///var/runtime/index.mjs:1206:1"
]
}
index.mjs
// Define handler function, the entry point to our code for the Lambda service
// We receive the object that triggers the function as a parameter
exports.handler = async (event) => {
// Extract values from event and format as strings
let name = JSON.stringify(`Hello from Lambda, ${event.firstName} ${event.lastName}`);
// Create a JSON object with our response and store it in a constant
const response = {
statusCode: 200,
body: name
};
// Return the response constant
return response;
};
JSON
{
"firstName":"Tyler",
"lastName":"Schnitzer"
}
It is suppose to be a simple hello world but I am confused why I can't get the event to work?
I am hoping someone can help explain this error and how to solve it, I tried looking through AWS Lambda trouble shooting page, but I still don't understand.
I had the same error. I deleted and recreated the lambda function with a runtime of Node.js 14.x, it works fine. The error was with Node.js 18.x, which is the default as of this writing.
I was following this tutorial, https://www.eventbox.dev/published/lesson/innovator-island/2-realtime/2-backend.html

Lambda connected to appsync always returns Lambda:Unhandled errorType no matter the custom Exception

I have a chat lambda that stores messages into dynamodb. If the user is not authorized to add the message, I need to return a custom error exception with unique errorType and message to my client.
I have setup my custom error using the documentation at https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-lambda.html
i.e.:
export default class ForbiddenError extends Error {
/**
* ForbiddenError constructor
* #param {string} name
* #param {string} message
*/
constructor(name = null, message = null) {
message = message || 'You are forbidden from performing this action.'
super(message)
this.name = name || 'Forbidden'
}
}
and then I throw the error inside my app via:
throw new ForbiddenError()
When I test my lambda locally, everything works nicely, the code encounters an error. I catch it and call
context.fail(error)
Even when I test my lambda using a testing lambda in the AWS console, I get a beautiful response containing both the message and the error type:
class ForbiddenError extends Error {
constructor(message) {
super(message)
this.name = 'ForbiddenError'
}
}
exports.handler = (event, context, callback) => {
throw new ForbiddenError('You are forbidden from performing this action.')
return context.fail('test');
};
and the error:
{
"errorType": "ForbiddenError",
"errorMessage": "You are forbidden from performing this action.",
"trace": [
"ForbiddenError: You are forbidden from performing this action.",
" at Runtime.exports.handler (/var/task/index.js:9:21)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
]
}
but when I call my lambda using appsync, suddenly only the message is passed into the error, but the errorType is always the same: Lambda:Unhandled i.e.:
{
"graphQLErrors": [
{
"path": [
"storeStreamChatMessage"
],
"data": null,
"errorType": "Lambda:Unhandled",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "You are forbidden from performing this action."
}
],
"networkError": null,
"message": "GraphQL error: You are forbidden from performing this action."
}
The response mapping template is the same is in the documentation:
ResponseMappingTemplate: |
#if($ctx.error)
$util.error($ctx.error.message, $ctx.error.type)
#end
$util.toJson($context.result)
I was trying to change the $ctx.error.type to $ctx.error.errorType, but then the errorType is returned as "Custom lambda error" and not "Forbidden".
I have tried using both the context.fail() and callback methods from the lambda exports.handler, both work nicely in the console but both only return the message when called from the appsync resolver.
I have tested that the context.fail(error) is indeed called in the lambda and that the exception is caught via .catch() statement before finally calling the context.fail(error)
Even cloudwatch displays the error with the message and errorType when the main lambda is called, so I'm suspecting an error in exepction and context.fail() returning
In the end, I stringified the error and passed it to my clients via the message column. Unfortunately, when I managed to pass the proper errorType via the resolver response mapping template, the returned error started returning "Custom Error" as the return errorType.

AWS API Gateway: Can't map thrown error from Lambda to Method Response using Integration Response

The issue
Using the Integration Response feature of AWS API Gateway, I can successfully handle errors thrown by Lambda. However, I'm having trouble mapping the Javascript error object to the mapping template. The error object looks like this.
{
"errorMessage": "Error: ABC123",
"errorType": "Error",
"stackTrace": [
"exports.handler (/var/task/index.js:9:11)"
]
}
Here's my Integration Response mapping for application/json
#set($errorMessage = $input.path('$.errorMessage'))
{
"message" : $errorMessage
}
What I've tried
Using this configuration, this is the entire response returned to the client: Unexpected 'E'. This is one string and is not contained in a JSON object.
This E that's referenced in the error is the first character from my thrown error message, which is used to match the Lambda Error Regex. I know this as I briefly changed the first letter to X and I got Unexpected 'X' as the response.
When I change the first line of my mapping template to this (mapping the entire object rather than attempting to just map the errorMessage property)
#set($errorMessage = $input.path('$'))
I get only the stack trace from the Javascript error object.
{
"message" : [
"exports.handler (/var/task/index.js:9:11)"
]
}
This would suggest that either the entire response object being returned to API Gateway is just the stackTrace property from the Javascript error. But to me, this doesn't make sense as something is picking up the errorMessage as thats where the Unexpected 'E' message is coming from.
Similarly, when I try and map the errorType property, I get the same error as it also starts with E. I can only successfully map the message property when I use the entire $ input object, or just the stackTrace property.
What am I doing wrong here?
Other relevant code
Here's the API Gateway Error Model. The message property is clearly marked as a string type yet it only works when I return an array. Note: this is the default code
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "Error Schema",
"type" : "object",
"properties" : {
"message" : { "type" : "string" }
}
}
Here's the Lambda function code
exports.handler = async (event, context, callback) => {
throw new Error(Error: ABC123);
};
I've figured it out. The solution is to use $input.json() rather than $input.path()
Here's my new mapping template
{
"errorMessage" : $input.json('$.errorMessage')
}

Intercept the Validation error from Flask restplus namespace class

Currently the Namespace parser validates the request arguments and throws error like
{
"errors": {
"file": "Missing required parameter in an uploaded file"
},
"message": "Input payload validation failed"
}
From the flask-app i want to intercept or handle these exceptions and send a customised response for consistency like
{
"errors": {
"file": "Missing required parameter in an uploaded file"
},
"message": "Input payload validation failed",
"id" : "some customer id "
}
Is it possible to handle this exception from app level instead of doing it for every api
According to this issue https://github.com/noirbizarre/flask-restplus/issues/530 there is a workaround to have a personalized message.
That said, it is possible to implement this with the definition of the BadRequest error handler and modify the data attribute:
#api.errorhandler(BadRequest)
def bad_request(self):
self.data.update({'id': 'some customer id'})
return {}, 400
Though, there is no clean way to avoid the empty dictionary return, as it is discarded.

Getting response from AWS Lambda function to AWS Lex bot is giving error?

I have created one AWS Lex bot and I am invoking one lambda function from that bot. When testing the lambda function I am getting proper response but at bot I am getting below error:
An error has occurred: Received invalid response from Lambda: Can not
construct instance of IntentResponse: no String-argument
constructor/factory method to deserialize from String value
('2017-06-22 10:23:55.0') at [Source: "2017-06-22 10:23:55.0"; line:
1, column: 1]
Not sure, what is wrong and where I am missing. Could anyone assist me please?
The solution to above problem is that we need to make sure response returned by lambda function, to be used at AWS lex chat bot should be in below format:
{
"sessionAttributes": {
"key1": "value1",
"key2": "value2"
...
},
"dialogAction": {
"type": "ElicitIntent, ElicitSlot, ConfirmIntent, Delegate, or Close",
Full structure based on the type field. See below for details.
}
}
By this, chat bot expectd DialogAction and corresponding elements in order to process the message i.e. IntentResponse.
Reference: http://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html
no String-argument constructor/factory method to deserialize from String value
You are getting this error because you must be passing string values in the response of lambda function. You have to pass a predefined json object blueprint in the response.
Because the communication between Lex and Lambda is not simple value passing like normal functions. Amazon Lex expects output from Lambda in a particular JSON format and data is sent to Lambda in a particular JSON. The examples are here: Lambda Function Input Event and Response Format.
And just copying and pasting the blueprint won't work because in some fields you have choose between some predefined values and in some fields you have to entry valid input.
For example in,
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled or Failed",
"message": {
"contentType": "PlainText or SSML",
"content": "Thanks, your pizza has been ordered."
}
}
you have assign a value "Fulfilled" or "Failed" to field 'fulfillmentState'. And same goes for 'contentType'.