Can't initialise Dialogflow Fulfillment WebhookClient in AWS Lambda - aws-lambda

According to the DialogFLow Fulfillment docs, the WebhookClient constructor needs Express HTTP request and response objects.
However, in Lambda function, I receive only the event (the request). How do I create the Express request and response objects?
I have tried this so far:
const {WebhookClient} = require('dialogflow-fulfillment');
exports.dialogflowFulfillment = async (event) => {
let response = {};
const agent = new WebhookClient({ event, response });
function sayNiceThings(agent) {
agent.add(`Nice to meet you!`);
}
let intentMap = new Map();
intentMap.set('Say Nice Things', sayNiceThings);
agent.handleRequest(intentMap);
};

Create an NodeJS Express App
Install serverless-http package for adding AWS Lambda bridge
Install dialogflow-fulfillment and actions-on-google npm packages.
npm init -f
npm install --save express serverless-http
npm install dialogflow-fulfillment
npm install actions-on-google
Create index.js file:
index.js:
=========
const serverless = require('serverless-http');
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
app.use(bodyParser.json({ strict: false }));
const {WebhookClient, Card, Suggestion} = require('dialogflow-fulfillment');
const request = require('request');
app.get('/', function (req, res) {
res.send('Hello World !!!\n');
console.log("Testing express lambda\n");
})
app.post('/', function (req, res) {
const agent = new WebhookClient({request: req, response: res});
function test_handler(agent) {
agent.add(`Welcome to my agent on AWS Lambda!`);
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('test-intent', test_handler);
agent.handleRequest(intentMap);
})
module.exports.handler = serverless(app);
Add configurations in serverless.yml:
serverless.yml
================
service: example-express-lambda
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: ap-southeast-1
functions:
app:
handler: index.handler
events:
- http: ANY /
- http: 'ANY {proxy+}'
Then deploy the lambda function.
Add the endpoint url in the Dialogflow fulfilment webhook url.
Reference:
https://serverless.com/blog/serverless-express-rest-api/

Related

Serverless Lambda function doesn't map to response correctly

I have a problem with correcltly returning the response of a Lambda function that I deploy using the Serverless framework:
module.exports.hello = async (event, context, callback) => {
const content = fs.readFileSync('./cn23_template.html', 'utf-8')
const Vue = require('vue')
const app = new Vue({
template: content,
data: function () {
return event
}
})
const renderer = require('vue-server-renderer').createRenderer()
const html = await renderer.renderToString(app)
const browser = await chromium.puppeteer.launch({
// Required
executablePath: await chromium.executablePath,
// Optional
args: chromium.args,
defaultViewport: chromium.defaultViewport,
headless: chromium.headless || true
});
const page = await browser.newPage();
await page.setContent(html);
let pdf = await page.pdf({ pageRanges: '1', format: 'a4', printBackground: true });
await browser.close();
return {
statusCode: 200,
headers: {
'Content-Type': 'application/pdf',
'Content-Length': pdf.length
},
body: pdf ? pdf.toString('base64') : null,
isBase64Encoded: true
}
}
My serverless.yml file:
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: post
integration: lambda
response:
headers:
Content-Type: "'Test'"
Cache-Control: "'max-age=120'"
The problem is that what I return from the function is not correctly mapped to the response. The response doesn't include the statusCode and headers, it just uses the whole returned object as body of the response.
Besides this, the headers as configured in the .yml are also not being used.
It seems like a very silly mistake, but I'm just doing exactly what is inside the Serverless API gateway docs.
So my question is: How do I properly configure the response properties so that the HTTP request gives the correct response using the Serverless framework?
You need to configure your lambda function to be invoked as a lambda-proxy event.
See Serverless Example Lambda Proxy

trying to fetch on aws lambda using serverless

I'm trying to run a simple script on AWS Lambda using Serverless to push it, the script fetches a url and returns it (a proxy), for some reason I can't see the response.
The script in question:
'use strict';
let axios = require('axios')
module.exports.hello = async (event, context) => {
let res = await axios.get('http://example.com')
return {
statusCode: 200,
body: JSON.stringify({
message: res,
input: event,
}),
}
};
My serverless YML:
service: get-soundcloud-tracks
provider:
name: aws
runtime: nodejs8.10
profile: home
functions:
hello:
handler: handler.hello
events:
- http:
path: users/create
method: get
cors: true
The solution was changing res to res.data inside the JSON.stringify

how to install mqtt library on AWS lambda function

i want to publish a mqtt message from AWS lambda function, i tried this
`exports.handler = function(event, context) {
// TODO implement
context.done(null, 'Hello from Lambda');
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://broker.hivemq.com');
var state = 'closed';
client.on('connect', () => {
console.log("connected to broker");
// Inform controllers that garage is connected
client.publish('garage/connected', 'true')
})
};
`
You need to create a zip file with the node_modules directory and the source file for your lambda.
e.g.
lamdba.js
node_modules/mqtt
node_modules/mqtt/package.json
...
You should use npm to install the package locally.
The details are described in the Lambda documentation here

Apollo GraphQL: Setting Port for HTTPBatchedNetworkInterface?

I'm trying to connect to a local dev environment via an IP address. I'm getting an error because HTTPBatchedNetworkInterface shows:
_uri: "http://10.0.1.10/graphql"
...when it needs to be:
"http://10.0.1.10:3000/graphql"
Here's my server-side setup code:
const localHostString = '10.0.1.10';
const METEOR_PORT = 3000;
const GRAPHQL_PORT = 4000;
const server = express();
server.use('*', cors({ origin: `http://${localHostString}:${METEOR_PORT}` }));
server.use('/graphql', bodyParser.json(), graphqlExpress({
schema,
context
}));
server.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
subscriptionsEndpoint: `ws://${localHostString}:${GRAPHQL_PORT}/subscriptions`
}));
// Wrap the Express server
const ws = createServer(server);
ws.listen(GRAPHQL_PORT, () => {
console.log(`GraphQL Server is now running on http://${localHostString}:${GRAPHQL_PORT}`);
console.log(`GraphiQL available at http://${localHostString}:${GRAPHQL_PORT}/graphiql`);
// Set up the WebSocket for handling GraphQL subscriptions
new SubscriptionServer({
execute,
subscribe,
schema
}, {
server: ws,
path: '/subscriptions',
});
});
What is the correct way to get the port number into HTTPBatchedNetworkInterface._uri?
Thanks in advance to all for any info.
Fixed. My framework is Meteor and I had to set ROOT_URL = 10.0.1.10:3000/.

body-parser.js not found when deploying

I got this error when I try to deploy node.js files.
Updated failed with Could not triggers. The error was Error: Module body-parser.js not found
Here is my code:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.set('views', 'cloud/views');
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.get('/hello', function(req, res) {
res.render('hello', { message: 'Congrats, you just set up your app!' });
});
app.listen();
I have npm install body-parser in my local machine. What should I do in order for Parse to recognize this module?
Parse's express framework is not a full node.js app. So you cannot directly use node.js packages that aren't supported by Parse.
Try this one instead,
var express = require('express');
var app = express();
app.set('views', 'cloud/views');
app.set('view engine', 'ejs');
app.use(express.json()); // to support JSON-encoded bodies
app.use(express.urlencoded()); // to support URL-encoded bodies
app.get('/hello', function(req, res) {
res.render('hello', { message: 'Congrats, you just set up your app!' });
});
app.listen();
Reference Docs # Parse.com

Resources