Alexa sends SessionEndedRequest on timeout then displays error card to user - aws-lambda

While testing my skill, if I do not reply and it times out, Alexa sends a SessionEndedRequest to my Lambda function.
Based on these docs: Handle Requests Sent by Alexa:
Your service cannot send back a response to a SessionEndedRequest.
Therefore, I am not responding to these requests.
But then my app shows a card with this message:
Skill response was marked as failure
(Skill Name)
Request Identifier: amzn1.echo-api.request.xxxxxxxxxxxxxxxxxxxxx
The target Lambda application returned a failure response
So what should we handle this request that does not give a response, and does not result in this error?
I use Node.js in Lambda, but a Python answer is fine too.

Are you sure the error in the card was for SessionEndedRequest only?
Generally, even if you send a response back to Alexa for a SessionEndedRequest, it won't be spoken.
You can handle a SessionEndedRequest like this in ask-nodejs-sdk-v2.
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
console.log("Inside SessionEndedRequestHandler");
return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
},
handle(handlerInput) {
console.log(`Session ended with reason: ${JSON.stringify(handlerInput.requestEnvelope)}`);
return handlerInput.responseBuilder.getResponse();
},
};

Related

Botframework | Twilio WhatsApp Adapter: how to fix "request doesn't contain a valid Twilio Signature"

I need to use Twilio as a channel for a chatbot (Bot Framework V4 NodeJS and the Twilio WhatsApp Adapter)
Messages send to Twilio via WhatsApp do reach the chatbot as a request. In the chatbot itself the validation of the request keeps failing.
const { TwilioWhatsAppAdapter } = require('#botbuildercommunity/adapter-twilio-whatsapp');
const whatsAppAdapter = new TwilioWhatsAppAdapter({
accountSid: '<Sid from Twilio console >',
authToken: '<>Auth token from Twilio console',
phoneNumber: '<phone number from Whatsapp Sandbox settings in Twilio>',
endpointUrl: 'url from Sandbox setting in Twilio'
});
The adapter is using a Twilio module. Twilio.validateRequest keeps returning false.
const signature = req.headers['x-twilio-signature'] || req.headers['X-Twilio-Signature'];
const authToken = this.settings.authToken;
const requestUrl = this.settings.endpointUrl;
const message = await this.retrieveBody(req);
return Twilio.validateRequest(authToken, signature, requestUrl, message);
I would appreciate some guidance. Otherwise I will need to figure our a way to debug this module
tnx
For the endpointUrl parameter I use is the one from my chatbot: https://mybot.azurewebsites.net/api/whatsapp/messages
for the phoneNumber parameter I tried multiple formats without succes:
whatsapp:+1XXXXXXXXXX
whatsapp:1XXXXXXXXXX
+1XXXXXXXXXX
1XXXXXXXXXX
I checked the source of the adapter and there are two possible causes.
No x-twilio-signature header. I checked the request headers and there seems to be a valid x-twilio-signature header in there.
The result of the twilio.validateRequest returns false. This method is taking authToken, signature, requestUrl and message. I checked them all and they seem fine.

With Cypress, how to get the response body of an api call triggered by a non-request event

I am testing my login page with cypress. The call to my api /api/auth/login is triggered automatically when the input field of the password reaches 4 characters. So in my cypress spec file, the command cy.get("password-input").type("1234") is enough to trigger the api call. How can I get the response body of that api call? I would like to get the token my api sends back.
In classic api calls with the cy.request command I can easily handle the response body, but I couldn't find how to access the response body when the api request is triggered by another event like here with the type event.
Currently, I have a workaround because my website stores the response.body.token in the localStorage, so I access the token with window and after a wait:
it("should get token", () => {
cy.visit("/login")
cy.get("[data-cy="login-input"]).type("myLogin")
cy.get("[data-cy="password-input"]).type("0001")
cy.wait(5000)
cy.window().then(window => {
cy.log(window.localStorage.getItem("myToken"))
})
})
But this feels gross... Could you give me the proper way to access the response body of the api call triggered by the type event?
You can use cy.intercept(), aliasing, and cy.wait():
it("should get token", () => {
cy
.intercept('/api/auth/login')
.as('token');
cy
.visit("/login");
cy
.get('[data-cy="login-input"]')
.type("myLogin");
cy
.get('[data-cy="password-input"]')
.type("0001");
cy
.wait('#token')
.then(intercept => {
// you can now access the request body, response body, status, ...
});
});
Useful reading:
https://docs.cypress.io/api/commands/intercept
https://docs.cypress.io/api/commands/intercept#Aliasing-individual-requests
https://docs.cypress.io/api/commands/wait
https://docs.cypress.io/api/commands/wait#Alias

API Gateway Websockets not sending to all clients

I'm using websockets with API Gateway and dynamoDB to maintain all connection IDs.
What I'm trying to do is when a new message comes in, a message is sent to all connected clients.
For example, inside the $default route a message will be received from the client. I'm then querying dynamo to get all connected ids and sending that message.
Querying dynamo:
const params = {
TableName: process.env.CONNECTIONS_TABLE,
IndexName: process.env.CONNECTIONS_COMPANY_INDEX,
KeyConditionExpression: "company = :company",
ExpressionAttributeValues: {
":company": data.company,
},
};
const response = await dynamodb.query(params).promise();
response.Items.forEach(async (item) => {
try {
await apig
.postToConnection({
ConnectionId: item.connectionId,
Data: JSON.stringify(data),
})
.promise();
} catch (e) {
if (e.statusCode === 410) {
console.log(e)
}
}
});
The issue I'm having is that it's only received on the clients after the second attempt. So the client sends a message "123" (the above code is run successfully and I've verified it's getting all connections, no errors) but nothing is received by the client. The client sends another message - "456", now both clients will receive the "123" message.
Any ideas why this would happen? I'd expect that each message sent, would receive the same message to all connected clients, not delayed and always one behind.
Thank you!
i faced with exact same issue. Then i just Remove integration response from the API gateway and leave the function return {}
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-routes-integrations.html#apigateway-websocket-api-overview-integrations-differences
In the HTTP protocol, in which requests and responses are sent
synchronously; communication is essentially one-way. In the WebSocket
protocol, communication is two-way. Responses are asynchronous and are
not necessarily received by the client in the same order as the
client's messages were sent. In addition, the backend can send
messages to the client.

Capture raw axios request from AWS Lambda

I have code that calls a vendor API to do a formdata upload of a file by axios from inside an AWS Lambda. The call returns a 400 error. If I run the code locally using the same node version v14 it works. I want to capture both raw requests and compare them for differences. How do I capture both raw requests? I've tried using ngrok and pipedream but they don't show the raw but decode the request and the file.
let response = null;
try {
const newFile = fs.createReadStream(doc);
const formData = new FormData();
formData.append("file", newFile);
formData.append("url", url);
const headers = {
Authorization: "Bearer " + token,
...formData.getHeaders(),
};
console.log("Headers: ", headers);
response = await axios.post(`${APIBASE}/file/FileUpload`, formData, {
headers,
});
console.log("file upload response", response);
} catch (err) {
console.log("fileupload error at API", err);
}
You might be able to just use a custom request interceptor and interrogate at the requests that way.
https://axios-http.com/docs/interceptors
You're not able to capture the request on the network level, as this is totally controlled by AWS. Maybe there's a way to do this when running in a VPC, but I don't think so.
You could simply use a tool such as axios debug logger to print out all of the request and response contents (including headers etc) before the request is made/after the response has arrived. This might provide some more information as to where things are going wrong.
As to the cause of the problem, it is difficult to help you there since you haven't shared the error message nor do we know anything about the API you're trying to call.
There are multiple ways to debug
axios debug logger .
AWS cloud watch where you can see all the logs. you can capture the request
and response.
Use postman to call the prod lambda endpoint and verify the response.

Cannot access error response body from client when using nginx + lua

I'm using the following lua script to forward all server responses that are served from Node. My error handling for a /signup route works as follows:
if authenticationResult.status ~= 201 then
...
ngx.status = authenticationResult.status
ngx.say(authenticationResult.body)
ngx.exit(401)
return
end
From the client I send a typical signup request like so, using the superagent-promise library:
request
.post(url)
.type('form')
.send(data)
.end()
.then((response) => {
console.log('the response', response)
})
.catch((error) => {
console.log('the error', error)
})
When I send a valid post request from the client, the response variable in the .then successfully contains the response body.
However, when I sent an improper post request with invalid credentials, neither the .then nor the .catch executes. Instead, the Chrome console immediately displays POST http://api.dockerhost/signup 401 (Unauthorized).
I would like to know what I can do differently to successfully access the server's error response and its contents, outside of just its status code.
Per the manual, you need to use ngx.HTTP_OK as the return if you want nginx to return content as part of the page. Otherwise it will simply return a 401.
ngx.status = authenticationResult.status
ngx.say(authenticationResult.body)
ngx.exit(ngx.HTTP_OK)
return

Resources