I have currently build a DialogFlow chatbot using Google Cloud Functions, Firebase. It all works good, but I would like to not use firebase at all, I would like to use Heroku, how can I make so that DialogFlow makes request to Heroku service.
I already know that I should add the URL of heroku and that has to be HTTPS and proper response format.
What I dont know is, how can I make the connection between DailogFlow and Heroku which is using node.js so I can send the responses such as :
sendResponse('Hello, this is responsing from Heroku')
Using firebase I have to had a function like this:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
if (request.body.result) {
processV1Request(request, response);
} else if (request.body.queryResult) {
// processV2Request(request, response);
} else {
console.log('Invalid Request');
return response.status(400).end('Invalid Webhook Request (expecting v1 or v2 webhook request)');
}
});
I dont know if I need this when using outside Firebase, at this case Heroku! also since I am not using firebase what will happen with this code:
functions.https.onRequest((request, response) => {
I dont have "functions" variable if I am not using firebase.
Most of the code can be used unchanged - Firebase Cloud Functions use node.js/express.js under the covers, and the Dialogflow libraries assume that the request and response objects are those from express.js with the JSON body parser middleware.
The line in question is syntactic sugar to have the Firebase Cloud Functions processor discover it and handle it. So you would replace that line
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
with something more like this
const express = require('express');
const app = express();
app.use( express.json() );
app.get('/', (req, res) => processWebhook( req, res ));
app.listen(3000, () => console.log('App listening on port 3000!'));
var processWebhook = function( request, response ){
// ... the console logging and all the processing goes here
Related
I'm trying to make a post request using appwrite SDK in Node JS express and Vue JS. The SDK requires me to create an api post request to create new storage bucket in appwrite. The DOCs for this particular request isn't explaining really how to create the api in node JS express. I'm really new to Node JS and I already succeeded at creating get request but whenever I create the post request I get 404 not found error.
Node JS express file (server.js):
In this file there is get users request API which works perfectly fine.
And there is create bucket post request which when being called in frontend it comes back with a 404
const express = require("express");
const path = require("path");
const app = express(),
bodyParser = require("body-parser");
port = 3080;
// Init SDK
const sdk = require("node-appwrite");
let client = new sdk.Client();
let users = new sdk.Users(client);
let storage = new sdk.Storage(client);
client
.setEndpoint("http://localhost/v1") // Your API Endpoint
.setProject("tailwinder") // Your project ID
.setKey(
"Secrer Key!"
); // Your secret API key
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, "../appwrite-app/build")));
//This get request works fine
//get user by ID
app.get("/v1/users/:id", (req, res) => {
let promise = users.get(req.params.id);
promise.then(
function (response) {
res.json(response);
},
function (error) {
console.log(error);
}
);
});
//This one isn't recognised in frontend
app.post("/v1/storage/buckets", function (req, res) {
let promise = storage.createBucket("bucket_id", "bucket_name", "file");
promise.then(
function (response) {
res.json(response);
},
function (error) {
console.log(error);
}
);
});
app.listen(port, () => {
console.log(`Server listening on the port::${port}`);
});
bucketsServices.js:
Here I'm using fetch post request to the api endpoint but it's not working.
export async function createBucket() {
const response = await fetch("/v1/storage/buckets", {
method: "POST",
});
return await response.json();
}
Addcomponent.vue:
Here I'm calling out the createBucket function from vue js file
bucketTesting() {
createBucket().then((response) => {
console.log(response);
});
},
The error which I assume it means that it's not reading my node js express post API:
bucketsService.js?993b:2 POST http://localhost:8080/v1/storage/buckets 404 (Not Found)
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
A screenshot of the same error:
Something is missing here and I can't really figure it out.
You are making request to localhost:8080 meanwhile your server is running at localhost:3080
I believe your vue is running at port 8080 that's why /v1/storage/buckets gets prefixed by localhost:8080
Try to provide full URL while making request
export async function createBucket() {
const response = await fetch("localhost:3080/v1/storage/buckets", {
method: "POST",
});
return await response.json();
}
Better way might be to add proxy to automatically redirect request to correct URL, but this should work for now. This article might help with how to setup proxy in vue
I have a NodeJS Application written in KoaJS,
app.ts
const app = new Koa();
app.use(healthCheck());
app.use(bodyParser());
app.use(errorHandler());
app.use(endpoints);
export default app;
main.ts
const port = process.env.PORT || 3000;
if (!isCloudFunctions()) {
app
.listen(port, () => {
console.info(`Listening at http://localhost:${port}`);
})
.on('error', console.error);
}
export const api = (req, res) => {
app.callback()(req, res);
}
The app works well on Cloud Runs,
I can deploy the app on Cloud Functions, but on Functions the app can only handle GET requests.
If I try a POST request, I get this error
InternalServerError: stream is not readable
at getRawBody (/workspace/node_modules/raw-body/index.js:112:10)
at readStream (/workspace/node_modules/raw-body/index.js:178:17)
at AsyncFunction.module.exports [as json] (/workspace/node_modules/co-body/lib/json.js:39:21)
at executor (/workspace/node_modules/raw-body/index.js:113:5)
at parseBody (/workspace/node_modules/koa-bodyparser/index.js:100:26)
at new Promise (<anonymous>)
at bodyParser (/workspace/node_modules/koa-bodyparser/index.js:85:25)
at next (/workspace/node_modules/koa-compose/index.js:42:32)
at /workspace/webpack:/sample-explore/apps/sample-api/src/middlewares/health-check.ts:10:12
at Generator.next (<anonymous>)
I re-created the application in ExpressJS, and it works fine with both Runs and Functions
However I am really like the native async/await , compose routing of KoaJS
Does anyone know the reason why KoaJS can not handle POST requests on Cloud Functions?
The json body is automatically parsed in google cloud functions (documentation) and the koa-bodyparser middleware can't handle already parsed bodies.
More info on this issue: https://github.com/koajs/bodyparser/issues/127
Suggested fixes, from the issue thread, are to either use ctx.req.body instead of ctx.request.body, you'll need to parse it when running locally of course.
Alternatively add a middleware that will support already parsed bodies.
function hybridBodyParser (opts) {
const bp = bodyParser(opts)
return async (ctx, next) => {
ctx.request.body = ctx.request.body || ctx.req.body
return bp(ctx, next)
}
}
app.use(hybridBodyParser())
I am a beginner to Twilio. I understand that I can get the status of the SMS send by having a statusCallback, so that the POST will happen to the callbackurl with the status of the message. But I am having troubles in creating that particular POST endpoint.
Here is what I have :
// Twilio API CALL
client.sendMessage({
to:userId,
from: metadata.myTwilioNumber,
body: message,
StatusCallback:'POST URL'
}, function(err, responseData) {
if (!err) {
} else {
logger.info(err);
}
My POST endpoint is a simple node js (request, response) endpoint.
var server = http.createServer ( function(request,response){
response.writeHead(200,{"Content-Type":"text\plain"});
if(request.method == "GET")
{
response.end("received GET request.")
}
else if(request.method == "POST")
{
console.log(request.CallStatus);
console.log(response);
console.log('receivedRequest');
response.end("received POST request.");
}
else
{
response.end("Undefined request .");
}
});
server.listen(4445);
Can someone help me in getting the status and messageID of the response? Currently, the POST is getting invoked but i am unable to get the message details and status.
Twilio developer evangelist here.
You are using the basic Node.js standard library http module which is going to make it a lot of work to extract the information from the POST request. Can I recommend you try something like express with body-parser instead.
You can do so by installing the two modules with npm:
npm install express body-parser
Then you can rewrite your incoming message application like this:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/', (req, res) => {
console.log(req.body.CallStatus);
res.sendStatus(200);
});
app.listen(4445, () => {
console.log('Application running on localhost:4445');
});
All the parameters that Twilio sends will be available on the req.body object.
Check out this tutorial on receiving SMS messages with Twilio in Node for a bit more detail.
So I am trying to make a simple proxy (I think that's the right word) and I've come up with some code that works fine locally. I can call 'firebase serve --only functions' and the function works fine and I get expected results. Now when I deploy this same code, and try calling it it just times out. I have no idea why, so I was hoping I could get some help.
Here's the code:
//Variables
const functions = require('firebase-functions');
const express = require('express');
const cors = require('cors');
const request = require('request');
//App
const app = express();
app.use(cors({ origin: true }));
//Endpoints
app.get('/**', function(req, res) {
request('https://example.com' + req.url, function(err, proxyRes, body) {
//Err
if (err) {
res.send('Error: ' + err.code);
return
}
//Res
res.status(200).send(body);
});
});
//Functions
exports.proxy = functions.https.onRequest(app);
HTTP functions will time out if they don’t send a response. This means your request() is probably failing, and it’s probably failing because, on the free Spark payment plan, you can’t make outgoing requests to services that Google doesn’t fully control.
Your function should send a response in all conditions in order to avoid a timeout. This means you should be checking for errors all the time.
I'm currently building an application built on top of AWS lambda functions, and am wanting to use Express as a middleware and gateway for requests that will then be passed to lambda.
However, I'm wondering if there is any risk in my setup below. Basically, I am defining all the acceptable routes, using router.all('/*') to catch every request, and then if the requested route is in the routes object and requested method is correct, it will authenticate the user and then run the lambda function. I will also add logic for authentication, which data to send to lambda, etc.
My questions are:
Is it acceptable to pass the res object to the lambda execution function?
Would it be better to authenticate in a different place, or is it fine to do so within the router.all function?
Are there any concerns with scalability/handling of many requests using this simple framework?
const express = require('express');
const app = express();
var AWS = require('aws-sdk');
var router = express.Router();
const routes = {
'lambdaFunctionA': { 'method' : 'POST', 'data' : 'body'},
'lambdaFunctionB': {'method' : 'GET', 'data' : 'queryParams'},
'lambdaFunctionC': {'method' : 'GET'}
}
router.all('/*', function (req, res) {
const path = req.path.split('/')[1];
if (path in routes) {
if ( routes[path].method == req.method ) {
//authentication logic here
//if authenticated, execute lambda
executeLambda(path,someDataHere, res);
}
else
{
res.status(405).send('Method not allowed');
}
}
else
{
res.status(404).send('Not found');
}
});
app.use('/api', router);
app.listen(8080);
function executeLambda(functionName,payload, res) {
var params = {
FunctionName: functionName,
Payload: payload
};
var lambda = new AWS.Lambda();
lambda.invoke(params, function (err, data) {
if (err) {
//need to handle errors here
res.send(err.stack);
} else {
res.send(JSON.parse(data.Payload));
}
});
}
Why not use express's builtin functionality to do this instead of doing yourself? No need to invent your own routing when express comes with it built-in
function lambdaHandler(req, res){
executeLambda(path, someDataHere, res);
}
function auth(next){
//...Do auth stuff
if(!auth) return next("router");
next();
}
router.use(auth);
router.post("/lambdaFunctionA", lambdaHandler)
router.get("/lambdaFunctionB", lambdaHandler)
router.get("/lambdaFunctionC", lambdaHandler)
Lookup express middleware
This way you get Express to handle the methods etc for you instead of having to handle it yourself. It can also validate.
And on every request it uses the middleware from router.use(auth) to authenticate before it ever gets to lambdaHandler
Also it is perfectly fine to pass res to the lambda handler. It's just an object.
As a side note:
Have you seen AWS API Gateway?
It can handle routing and uses lambdas just like in your use case. Without having to manage your own server.