I am trying to integrate dialogflow with firebase using Webhook.
The response I receive is:
"webhookStatus": {
"code": 13,
"message": "Webhook call failed. Error: 500 Internal Server Error."
}
Webhook is: https://us-central1-miarduino-844c8.cloudfunctions.net/receiveAssistantRequests
Firebase rules are:
{
/* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
"rules": {
".read": true,
".write": true
}
}
index.js I have used is:
const functions = require('firebase-functions');
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
const admin = require('firebase-admin');
admin.initializeApp();
const DialogflowApp = require('actions-on-google').DialogflowApp;
exports.receiveAssistantRequests = functions.https.onRequest((request, response) => {
const app = new DialogflowApp({ request: request, response: response });
function handlerRequest(app) {
const device = app.getArgument('devices');
const status = app.getArgument('status');
return admin.database().ref(`/automation/${device}/value`).set(status)
.then(snapshot => {
app.ask(`Ok, switching ${device} ${status}. Do you want to control anything else?`);
});
}
app.handleRequest(handlerRequest);
});
If I use soapUI for making the request to: https://us-central1-miarduino-844c8.cloudfunctions.net/receiveAssistantRequests
I get:
HTTP/1.1 500 Internal Server Error
Content-Type=text/plain; charset=utf-8
X-Content-Type-Options=nosniff
X-Cloud-Trace-Context=7327cb053558c4598e01b0218e61e5cf;o=1
Date=Thu, 08 Aug 2019 10:19:12 GMT
Server=Google Frontend
Content-Length=36
Alt-Svc=quic=":443"; ma=2592000; v="46,43,39"
Error: could not handle the request
Has anyone idea regarding how to solve this issue?
Not sure if the issue is located in Dialogflow or in Firebase
This might help you.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp({
databaseURL: "YOUR_DATABASE_URL"});
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({request,response});
console.log('dailog firebase admin'+agent);
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
}
Related
I have an api in express js that stores token in cookie on the client-side (react). The cookie is generated only when the user logins into the site. For example, when I test the login api with the postman, the cookie is generated as expected like this:
But when I log in with react.js then no cookie is found in the browser. Looks like the cookie was not passed to the front end as the screenshot demonstrates below:
As we got an alert message this means express api is working perfectly without any error!!
Here is my index.js file on express js that includes cookie-parser middleware as well
require("dotenv").config();
const port = process.env.PORT || 5050;
const express = require("express");
const app = express();
const cors = require("cors");
const authRouter = require("./routes/auth");
var cookieParser = require('cookie-parser')
connect_db();
app.use(express.json());
app.use(cookieParser())
app.use(cors());
app.use("/" , authRouter);
app.listen(port , () => {
console.log("Server is running!!");
})
Code for setting up the cookie from express api only controller
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require('bcrypt')
const login = async (req, res) => {
const { email, password } = req.body;
try {
const checkDetails = await User.findOne({ email });
if (checkDetails) {
const { password: hashedPassword, token, username } = checkDetails;
bcrypt.compare(password, hashedPassword, function (err, matched) {
if (matched) {
res.cookie("token", token, { expires: new Date(Date.now() + (5 * 60000)) , httpOnly: true }).json({ "message": "You logged in sucessfully!" });
} else {
res.status(500).json({ "message": "Wrong password" });
}
});
} else {
res.status(500).json({ "message": "Wrong email" });
}
} catch (error) {
console.log(error.message);
}
}
Here is the react.js code that I am using to fetch data from api without using a proxy in package.json file
if (errors.length === 0) {
const isLogin = await fetch("http://localhost:5000/api/login", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: {
"Content-Type": "application/json"
}
});
const res = await isLogin.json();
if(res) alert(res.message);
}
I want to get to know what is the reason behind this "getting cookie in postman but not in the browser". Do I need to use any react package?
The network tab screenshot might help you.
If I see in the network tab I get the same cookie, set among the other headers
To my understanding, fetch doesn't send requests with the cookies your browser has stored for that domain, and similarly, it doesn't store any cookies it receives in the response. This seems to be the expected behaviour of fetch.
To override this, try setting the credentials option when making the request, like so:
fetch(url, {
// ...
credentials: 'include'
})
or, alternatively:
fetch(url, {
// ...
credentials: 'same-origin'
})
You can read more about the differences between the two here.
I got my error resolved with two changings in my code
In front end just added credentials: 'include'
fetch(url, {
method : "POST"
body : body,
headers : headers,
credentials: 'include'
})
And in back end just replaced app.use(cors()); to
app.use(cors({ origin: 'http://localhost:3000', credentials: true, exposedHeaders: ['Set-Cookie', 'Date', 'ETag'] }))
That's it got resolved, Now I have cookies stored in my browser!!! Great. Thanks to this article:
https://www.anycodings.com/2022/01/react-app-express-server-set-cookie-not.html
during development i also faced same things, let me help you that how i solve it,
Firstly you use proxy in your react package.json, below private one:-
"private": true,
"proxy":"http://127.0.0.1:5000",
mention the same port on which your node server is running
Like:-
app.listen(5000,'127.0.0.1',()=>{
console.log('Server is Running');
});
above both must be on same , now react will run on port 3000 as usual but now we will create proxy to react So, react and node ports get connected on same with the help of proxy indirectly.
Now, when you will make GET or POST request from react then don't provide full URL, only provide the path on which you wants to get hit in backend and get response,
Example:-
React side on sending request, follow like this:-
const submitHandler=()=>{
axios.post('/api/loginuser',
{mobile:inputField.mobile,password:inputField.password})
.then((res)=>{
console.log(res);
})
.catch((err)=>{
console.log(err);
})
}
Node side where it will hit:-
app.post('/api/loginuser', async(req,res)=>{
//Your Code Stuff Here
res.send()
}
on both side same link should hit, it is very important
it will 100%.
don't forget to mention
on node main main where server is listening
I have issue with firebase i try to deploy a new functions but i got this error:
Function failed on loading user code. Error message: Error: please examine your function logs to see the error cause: https://cloud.google.com/functions/docs/monitoring/logging#viewing_logsFunctions deploy had errors with the following functions:api
my index.js in the functions folder is:
const functions = require("firebase-functions");
const express = require("express");
const cors = require("cors");
const stripe = require("stripe")("--TOKEN_HERE--");
// API
// - App config
const app = express();
// - Middlewares
app.use(cors({ origin: true }));
app.use(express.json());
// - API routes
app.get("/", (request, response) => response.status(200).send("hello world"));
app.post("/payments/create", async (request, response) => {
const total = request.query.total;
console.log("Payment Request Recieved BOOM!!! for this amount >>> ", total);
const paymentIntent = await stripe.paymentIntents.create({
amount: total, // subunits of the currency
currency: "usd",
});
// OK - Created
response.status(201).send({
clientSecret: paymentIntent.client_secret,
});
});
// - Listen command
exports.api = functions.https.onRequest(app)
Anyone have an idea?
I am writing my first Cloud Function which works great locally but doesn't work the moment I deployed it to Firebase. I am trying to invoke a Cloud function which will send an email via a HTTP request using Flutter Web. I read online and suspect it might be be because I cant return the promise. How do I ensure the asynchronous calls to be completed?
const nodemailer = require('nodemailer');
const cors = require('cors')({origin: true});
/**
* Here we're using Gmail to send
*/
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'dummyaccount#gmail.com',
pass: 'dummypassword'
}
});
exports.sendMail = functions.https.onRequest((req, res) => {
cors(req, res, () => {
return transporter.sendMail(req.body, (erro, info) => {
if(erro){
return res.send(erro.toString());
}
return res.send('Message send');
});
});
});
const admin = require('firebase-admin');
admin.initializeApp();
This is my Http Request using Dart for Flutter Web
void httpCallFunction() async {
var url =
'https://us-central1-fire-station-ope-blablala.cloudfunctions.net/sendMail';
var response = await http.post(
url,
body: json.encode({
"from": "Dummy Guy <Do-Not-Reply#gmail.com>",
"to": "$_email",
"subject": "Your Booking has been approved!!",
"html": approvedMessageTosent,
}),
headers: {
'Content-type': 'application/json',
},
);
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');
}
I went through a rollercoaster to solve this issue. So apparently the cloud function log came back with status code 204 and said that my 'Request body is missing data' but I could see that my data was being sent.
So I found another guy faced the exact same issue as I did in this link: Dart json.encode is not encoding as needed by Firebase Function
Essentially I had to wrap my data in a key called 'data'.
{
"data":{
"to":"john#doe.com",
"displayName":"Johnny",
"from":"JaneDoe",
}
}
https://firebase.google.com/docs/functions/callable-reference#request_body
I was trying create a react project with firebase as backend(firebase functions + express). I am using a post route which is expected to receive a json as request body and respond with 200 status once the data is inserted into firestore I am use axios to send the post request along with that, the rote responds with a 500 error in postman request and working fine with a simple html form.
code for route (Express + firebase functions)
/*imports*/
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const express = require('express');
var bodyParser = require('body-parser');
const cors = require('cors');
const jsonParser = bodyParser.json();
var app = express();
app.use(jsonParser);
/*route*/
app.post('/create',jsonParser,(request, response)=>{
(async ()=>{
try{
var data = {
fullName : request.body.name,
email : request.body.email
};
await db.collection('signup').doc("/"+request.body.email+"/").create(data);
return response.status(200).json(data);
}catch(error)
{
console.log(error);
console.log("name on body"+request.body.name);
return response.status(500).send("data"+request.body.name);
}
})();
});
and this is how I post data from front end
await axios.post(API_BASE_URL+endpoint,body,config).then(function(response){
return response;
}).catch(function(error){
throw error;
});
following is what I tried to post as body
let data = {
fullName: "John Doe",
email: "john#examplemail.com",
};
I am trying to built a local server for dialogflow bot using a node.js framework but ,not able to establish one .
I am using serveo.net as tunneling as ngrok doesn't work as it is blocked by my institute.
I am able to launch a server but unable to get a response from it back to the dialogflow agent.
'use strict';
const {WebhookClient} = require('dialogflow-fulfillment');
const express = require("express"); //express
const bodyParser = require("body-parser"); //body-parser
const app = express(); //app
app.use(bodyParser.json);
app.use(bodyParser.urlencoded({
extended: true
})
);
const WEBHOOK = 'webhook';
app.get('/', (req, res) => res.send('online'));
app.post('/webhook', express.json(), (request, respond) => {
const agent = new WebhookClient({
request,
response
});
function webhookprocessing(request, response) {
const agent = new WebhookClient(request, response);
const action = agent.intent;
if (action == WEBHOOK) {
agent.add("My name is karthik");
} else {
agent.add("karthik");
}
}
function welcome() {
agent.add('Welcome to my agent!')
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set("webhook", webhookprocessing);
agent.handleRequest(intentMap)
//const agentPath = agent.entitiesClient.projectAgentPath("master-bot-53dee");
//console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
//console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
//console.log("Server Hit");
});
app.listen(process.env.PORT || 5000);
edit1: I am getting a request from google dialogflow but my local server isn't sending a response.
edit2: The response payload shown received by dialogflow from my node is
{
"responseId":"efaf7898-74de-4727-bf2a-8eeb32ba570a-baaf0c1f",
"queryResult":{
"queryText":"1",
"parameters":{
"number":1
},
"allRequiredParamsPresent":true,
"fulfillmentMessages":[
{
"text":{
"text":[
""
]
}
}
],
"intent":{
"name":"projects/master-bot-53dee/agent/intents/15b96d92-4adb-4657-8b15-ebdf7df180b4",
"displayName":"webhook"
},
"intentDetectionConfidence":1,
"diagnosticInfo":{
"webhook_latency_ms":4991
},
"languageCode":"en"
},
"webhookStatus":{
"code":4,
"message":"Webhook call failed. Error: Request timeout."
}
}
and the request payload send by dialogflow is
{
"responseId":"efaf7898-74de-4727-bf2a-8eeb32ba570a-baaf0c1f",
"queryResult":{
"queryText":"1",
"parameters":{
"number":1
},
"allRequiredParamsPresent":true,
"fulfillmentMessages":[
{
"text":{
"text":[
""
]
}
}
],
"intent":{
"name":"projects/master-bot-53dee/agent/intents/15b96d92-4adb-4657-8b15-ebdf7df180b4",
"displayName":"webhook"
},
"intentDetectionConfidence":1,
"languageCode":"en"
},
"originalDetectIntentRequest":{
"payload":{
}
},
"session":"projects/master-bot-53dee/agent/sessions/d1205a66-9eda-d79c-7677-75eeb402e7e5"
}
The request sent by dialogflow reaches my public url created by my tunneling software but there isn't any response from the localhost .
This image is a screenshot of my console where I appear to be getting a post request but there isn't a response appearing on dialogflow.
I have used this url to refer webhook url https://excedo.serveo.net/.
app.post('/webhook', express.json(), (request, respond) => { // error name of the param doesn't match its usage
This line you are using respond as the parameter and passing and using response instead .Please change line to -
app.post('/webhook', express.json(), (request, response) => {
The webhook isn't being called at the /webhook path because the configuration in Dialogflow is telling it the webhook is at /. If you change this to https://excedo.serveo.net/webhook it will be routed correctly.