Error- Warning, FIREBASE_CONFIG environment variable is missing. Initializing firebase-admin will fail - google-cloud-firestore

I tried to connect my existing firestore database to Dialogflow fulfillment. The function deployed to Google CLoud Function successfully but I cannot add data to my database. I have tried to change the node version 8 but still failed. Please help me.
Index.js
'use strict';
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
admin.initializeApp({
apiKey: "Axxxx",
authDomain: "/xxxxx.firebaseio.com",
databaseURL: "https:/xxxxxx.firebaseio.com",
projectId: "mxxxxx8",
storageBucket: "xxxxx.com",
});
const functions = require('firebase-functions');
const settings = {timestampsInSnapshots: true};
var db = admin.firestore();
admin.firestore().settings({ timestampsInSnapshots: true });
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
// intentMap.set('your intent name here', yourFunctionHandler);
// intentMap.set('your intent name here', googleAssistantHandler);
agent.handleRequest(intentMap);
});
package.json
{
"name": "dialogflowFirebaseFulfillment",
"description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "8"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "^2.2.0",
"firebase-admin": "~7.1.1",
"firebase-functions": "^2.2.1",
"dialogflow": "^0.6.0",
"dialogflow-fulfillment": "^0.5.0"
}

The solution is upgrade your Firebase project plan to Blaze Plan. Then make a new Dialogflow agent under that Firebase project.

Your Firebase initialization seems wrong. Here's how you should do it:
.
.
.
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: 'https://<DATABASE_NAME>.firebaseio.com'
});
.
.
.
This should work.

Based on the documentation it should be like this,
serviceAccount = require('./serviceAccount.json');
const adminConfig = JSON.parse(process.env.FIREBASE_CONFIG);
adminConfig.credential = admin.credential.cert(serviceAccount);
admin.initializeApp(adminConfig);

Related

MERN Stack Error: how to resolve "Cannot GET /" error when running backend server?

I know there are loads of posts on stack overflow about this issue. However, I can't find the solution to this problem when I try what is suggested on the other posts and some answers I don't find them very clear. That's why, I thought it useful to ask this question by emphasizing where my mistake is. So I am currently working on the backend of my MERN application, when I run my server I get the following message in my terminal .Personally I am a beginner and I was expecting it to tell me that everything went successfully and it automatically opens a tab for me on my browser. When I manually open the tab at the specified address i.e.: http://localhost:5000/, I get the error Cannot GET / I don't even know what it means. Here are the contents of my files:
config.js
module.exports = {
PORT: process.env.PORT || 4000,
MONGODB_URI: process.env.MONGODB_URI || "mongodb://localhost:27017/facebook_clone",
JWT_SECRET: process.env.JWT_SECRET || "itssecret",
JWT_EXP: process.env.JWT_EXPIRE || '10h',
ADMIN_EMAIL: process.env.ADMIN_EMAIL || "admin#gmail.com",
ADMIN_PASSWORD: process.env.ADMIN_PASSWORD || "admin#123",
}
index.js
const express = require('express')
const cors = require('cors')
const mongoose = require('mongoose')
require("dotenv").config()
const app = express()
const http = require('http')
const server = http.createServer(app)
const io = require('socket.io')(server)
const UserRoutes = require('./routes/User')
const AuthRoutes = require('./routes/Auth')
const PostRoutes = require('./routes/Post')
const PORT = process.env.PORT || 5000
const {MONGODB_URI} = require("./config")
app.use(cors())
app.use(express.json())
app.use((req, res, next) => {
io.req = req
req.io = io
next()
})
app.use('/api/auth', AuthRoutes)
app.use('/api/user', UserRoutes)
app.use('/api/post', PostRoutes)
require('./socket')(io)
mongoose
.connect(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => {
console.log('database connected')
server.listen(PORT, () => console.log(`server started on port ${PORT}`))
})
.catch((err) => console.log(err))
package.json
{
"name": "server",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"dev": "nodemon index.js",
"start": "node index.js"
},
"dependencies": {
"bcrypt": "^5.0.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.18.1",
"heroku": "^7.60.2",
"jsonwebtoken": "^8.5.1",
"mongodb": "^3.7.3",
"mongoose": "^5.10.7",
"multer": "^1.4.2",
"socket.io": "^2.4.1"
},
"devDependencies": {
"nodemon": "^2.0.4"
}
}
I even tried to change the port number from 4000 to 5000 in my config.js file but without success. And so I hope more experienced members of the community can help me. Thanks a lot !
probably the reason is that you did not specify that route in your app in your routes for example app.use("/"), otherwise in your browser URL if you navigate to one of the routes below you'll get a result:
HTTP://localhost:5000/api/auth
HTTP://localhost:5000/api/user
HTTP://localhost:5000/api/post

can't socket.emit() in Cloud Run server environment

My site is using socket.io. Locally it works great. But after deploying with gcloud run deploy the socket.emit() in my javascript file, wont communicate with my app.js file/server.
js file
socket.emit("connectedforrecording");
app.js file
function newConnection(socket) {
console.log("Connection with ID: " + socket.id);
socket.on("connectedforrecording", () => {
console.log("anything??")
// here are connections from /new
console.log("record page", socket.id);
let tempDir ="./tempDirs/temp"+socket.id;
fs.mkdir(tempDir, () => {
fs.chmod(tempDir, "777", () =>{console.log("chmod", tempDir);});
console.log(tempDir);}); // temp dirextory for audio files
var audioReceived = 0;//this flags if writing/written to canvas, so directory is not deleted!
let start = Math.floor(Math.random()*(canvasSize-30)); //start position for recording in secs
console.log(start);
let userdetailsrecieved = 0;
let userDetails = {index: 0, start:0, name:"anonymous", link:"", freq:1000, colour: "#EF863F", sharpness:0.5, sentence:""}; // create a json object with default numbers
userDetails.start = start; // add attribute: start
// request sound from server
socket.on("requestSound", ()=>{
socket.emit("flag", start); // sends start pos to client
sendCanvasSection("./canvas.raw", start, socket);
//////////////////////////////////////n.b. !!!!
// let s = tools.sentence();
let s = sentence();
console.log(s);
console.log("color: ", s.colour);
socket.emit("sentence", s);
// userDetails.colour = {"r":parseInt(hex.slice(1,3), 16), "g":parseInt(hex.slice(3,5), 16), "b":parseInt(hex.slice(5,7), 16)};
userDetails.colour = hexToRgb(s.colour[0]);
userDetails.sharpness = 1- s.angle.v;
userDetails.sentence = s.sentence;
console.log(userDetails);
});
});
});
}
Your question is difficult to answer because you're missing important components of your solution:
Minimally-reproducible example
Explanations of how you deployed to Cloud Run
What you observed, logs and other output
Arbitrary code deployed to Cloud Run cannot be expected to run.
In fact, there's a Cloud Run contract to which code must adhere.
Principally (!), Cloud Run requires a server that listen on (whatever value but generally 8080) is assigned to the PORT environment variable.
WebSockets can be used with Cloud Run services.
Cloud Run provides an in-memory file system (see link) and so you can use Node's fs and can use e.g. fs.mkdir.
Here's my minimally-repro example of a WebSockets solution on Cloud Run that summarizes my attempt to answer your question. I mashed-up Google's WebSockets sample and the intro from Socket.IO
BILLING="[[YOUR-BILLING-ACCOUNT]]"
PROJECT="[[YOUR-PROJECT-ID]]"
REGION="[[YOUR-REGION]]" # e.g. "us-west1"
NAME="[[YOUR-SERVICE]]" # e.g. "websockets"
SERVICES="artifactregistry cloudbuild run"
for SERVICE in ${SERVICES}
do
gcloud services enable ${SERVICE}.googleapis.com \
--project=${PROJECT}
done
gcloud beta run deploy ${NAME} \
--source . \
--allow-unauthenticated \
--region=${REGION} \
--project=${PROJECT} \
--timeout 3600
# Browse
ENDPOINT=$(\
gcloud beta run services describe ${NAME} \
--project=${PROJECT} \
--region=${REGION} \
--format="value(status.url)")
curl --request GET ${ENDPOINT}
I was lazy, the only output is in the client's developer console logs and the server's logs:
FILTER="
resource.type = \"cloud_run_revision\"
resource.labels.service_name = \"${NAME}\"
resource.labels.location = \"${REGION}\"
"
gcloud logging read "${FILTER}" \
--project=${PROJECT} \
--format="value(textPayload)"
Yields:
Listening on 8080
[./tempDirs/templDX9eww0pDOpN63JAAAB] entered
[./tempDirs/templDX9eww0pDOpN63JAAAB] done
[./tempDirs/templDX9eww0pDOpN63JAAAB] chmod
hello from client: 5,6,[object Object]
And the code:
package.json:
{
"name": "websockets",
"version": "0.0.1",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.17.3",
"socket.io": "^4.4.1"
}
}
}
index.js:
// Use server.js
const server = require('./server');
// Cloud Run contract requires server on PORT (or 8080)
const PORT = parseInt(process.env.PORT) || 8080;
server.listen(PORT, () =>
console.log(`Listening on ${PORT}`)
);
process.on('SIGTERM', () => {
process.exit(0);
});
module.exports = server;
server.js:
const express = require('express');
const fs = require('fs')
const app = express();
app.use(express.static(__dirname + '/'));
app.get('/', async (req, res) => {
res.render('index');
});
const server = require('http').Server(app);
const io = require('socket.io')(server);
io.on('connection', socket => {
socket.emit("hello from server", 1, "2", { 3: Buffer.from([4]) });
// Proof of fs
// From your code
let tempDir ="./tempDirs/temp"+socket.id;
fs.mkdir(tempDir, () => {
console.log(`[${tempDir}] entered`);
fs.chmod(tempDir, "777", () =>{
console.log(`[${tempDir}] chmod`);
});
console.log(`[${tempDir}] done`);
});
socket.on("hello from client", (...args) => {
console.log(`hello from client: ${args}`);
});
});
module.exports = server;
index.html:
<html>
<head></head>
<body></body>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io("", {
transports: ["websocket"],
});
socket.emit("hello from client", 5, "6", { 7: Uint8Array.from([8]) });
socket.on("hello from server", (...args) => {
console.log(`hello from server: ${args}`);
});
</script>
</html>

After successfully deploying Next.js app on AWS Amplify, https://www.example.com/api/any-route showing below error in console

The app is deployed successfully but the API routes (/pages/api) are not working as expected, showing below error in the console.
Build is successful and deployed on aws-amplify, I have added environment variables correctly, don't know why this is happening?
Does aws-amplify doesn't support serverless functions writer inside /api folder??
{
"error": {
"message": "connect ECONNREFUSED 127.0.0.1:80",
"name": "Error",
"stack": "Error: connect ECONNREFUSED 127.0.0.1:80\n at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1148:16)",
"config": {
"url": "undefined/campaigns",
"method": "get",
"headers": {
"Accept": "application/json, text/plain, */*",
"User-Agent": "axios/0.21.4"
},
"auth": {},
"transformRequest": [null],
"transformResponse": [null],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1,
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
}
},
"code": "ECONNREFUSED"
}
}
Here is the code
import axios from 'axios';
import Cors from 'cors';
import rateLimit from '../../../utils/rate-limit';
import initMiddleware from '../../../lib/init-middleware';
// Initialize the cors middleware
const cors = initMiddleware(
Cors({
methods: ['POST'],
origin: ['https://www.example.com', /\.example\.com$/],
})
);
const limiter = rateLimit({
interval: 60 * 1000, // 60 seconds
uniqueTokenPerInterval: 500, // Max 500 users per second
});
const handler = async (req, res) => {
await cors(req, res);
if (req.method === 'GET') {
try {
await limiter.check(res, 50, 'CACHE_TOKEN');
const { data } = await axios.get(`${process.env.BASE_URL}/campaigns`, {
auth: {
username: process.env.MAIL_SERVER_USERNAME,
password: process.env.MAIL_SERVER_PASSWORD,
},
});
return res.status(200).json(data);
} catch (error) {
return res.status(429).json({ error });
}
} else {
try {
await limiter.check(res, 10, 'CACHE_TOKEN'); // 10 requests per minute
return res.status(200).json('not allowed');
} catch (err) {
return res.status(429).json({ error: 'Rate limit exceeded' });
}
}
};
export default handler;
I figured out that environment variables are not getting reflected, so did some googling; found this solution and it worked for me.
Add your desired environment variable in the Amplify Console-like normal (steps)
Update (or create) your next.config.js file with the environment variable you added in the Amplify Console. E.g if you created an environment variable named MY_ENV_VAR in the console in step 1) above, then you would add the following:
module.exports = {
env: {
MY_ENV_VAR: process.env.MY_ENV_VAR
}
};
Now after your next build you will be able to reference your environment variable (process.env.MY_ENV_VAR) in your SSR lambdas!
Here is the link: Github
Ran into the same problem Amplify only supports NextJS 11 at the moment. If you go with the default settings it will use the latest NextJS 12 and /api routes wont work, they return a 503 with a cloudformation permission error.
Specify next 11.1.3 in your package.json
https://aws.amazon.com/about-aws/whats-new/2021/08/aws-amplify-hosting-support-next-js-version-11/
I also faced that problem. Amplify does not support v12 of next. Simply downgrade your next.js version in package.json to v1.1.3 and your routes will work as normal.
Best regrets.
Artem Meshkov

MERN-Stack Heroku - Cannot GET /

Trying to get a MERN-Stack to Deploy on Heroku I've added MONGOBD_URI as a key in Config Vars on Heroku and added the MongoDB Atlas value.
Heroku is connected directly to the Github repo and not through the Heroku CLI. I have it set to auto-deploy but recently redeployed it manually.
This was the Heroku Build Log:
-----> Node.js app detected
-----> Creating runtime environment
NPM_CONFIG_LOGLEVEL=error
NODE_VERBOSE=false
NODE_ENV=production
NODE_MODULES_CACHE=true
-----> Installing binaries
engines.node (package.json): unspecified
engines.npm (package.json): unspecified (use default)
Resolving node version 12.x...
Downloading and installing node 12.20.0...
Using default npm version: 6.14.8
-----> Restoring cache
Cached directories were not restored due to a change in version of node, npm, yarn or stack
Module installation may take longer for this build
-----> Installing dependencies
Installing node modules
> nodemon#2.0.6 postinstall /tmp/build_b41198ca_/node_modules/nodemon
> node bin/postinstall || exit 0
Love nodemon? You can now support the project via the open collective:
> https://opencollective.com/nodemon/donate
added 290 packages in 6.983s
-----> Build
-----> Caching build
- node_modules
-----> Pruning devDependencies
removed 1 package and audited 289 packages in 2.051s
17 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
-----> Build succeeded!
-----> Discovering process types
Procfile declares types -> (none)
Default types for buildpack -> web
-----> Compressing...
Done: 33M
-----> Launching...
Released v17
https://jms-r0b.herokuapp.com/ deployed to Heroku
The browser(Chrome) only renders Cannot GET / and consol.log()'s GET https://jms-r0b.herokuapp.com/ 404 (Not Found) jms-r0b.herokuapp.com/:1
This is the LINK to my repo.
Here's how my server.js is setup:
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cors = require("cors");
const mongoose = require("mongoose");
const todoRoutes = express.Router();
const PORT = process.env.PORT || 4000;
let Todo = require("./models/todo.model");
app.use(cors());
app.use(bodyParser.json());
// Express data parsing
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static("public"));
const URI = process.env.MONGODB_URI || "mongodb://localhost/todos";
mongoose.connect(
URI,
{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false,
},
(err) => console.log(err)
);
const connection = mongoose.connection;
connection.once("open", () => {
console.log("MongoDB database connection established successfully");
});
todoRoutes.route("/").get((req, res) => {
Todo.find((err, todos) => {
if (err) {
console.log(err);
} else {
res.json(todos);
}
});
});
todoRoutes.route("/:id").get((req, res) => {
let id = req.params.id;
Todo.findById(id, (err, todo) => {
res.json(todo);
});
});
todoRoutes.route("/update/:id").post((req, res) => {
Todo.findById(req.params.id, (err, todo) => {
if (!todo) {
res.status(404).send("data is not found");
} else {
todo.todo_description = req.body.todo_description;
todo.todo_responsible = req.body.todo_responsible;
todo.todo_priority = req.body.todo_priority;
todo.todo_completed = req.body.todo_completed;
todo
.save()
.then((todo) => {
res.json("Todo updated!");
})
.catch((err) => {
res.status(400).send("Update not possible");
});
}
});
});
todoRoutes.route("/add").post((req, res) => {
let todo = new Todo(req.body);
todo
.save()
.then((todo) => {
res.status(200).json({ todo: "todo added successfully" });
})
.catch((err) => {
res.status(400).send("adding new todo failed");
});
});
todoRoutes.route("/delete/:id").delete((req, res) => {
Todo.findByIdAndRemove(req.params.id, (err, todo) => {
if (!todo) {
res.status(404).send("data is not found");
} else {
res.status(200).json({
msg: todo,
});
}
});
});
app.use("/todos", todoRoutes);
app.listen(PORT, () => {
console.log("http://localhost:" + PORT);
console.log(".env.PORT:" + process.env.PORT);
});
and this is how my root package.json looks:
{
"name": "rob",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start:dev": "cd client && npm start",
"client": "cd client && npm run start",
"start": "concurrently \"node server/server.js\" \"npm run client\"",
"dev": "concurrently \"nodemon server/server.js\" \"npm run client\""
},
"repository": {
"type": "git",
"url": "git+https://github.com/WasteOfADrumBum/r0b.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/WasteOfADrumBum/r0b/issues"
},
"homepage": "https://github.com/WasteOfADrumBum/r0b#readme",
"dependencies": {
"bcryptjs": "^2.4.3",
"concurrently": "^5.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-mongo-sanitize": "^2.0.0",
"express-rate-limit": "^5.1.3",
"helmet": "^4.2.0",
"hpp": "^0.2.3",
"ini": "^2.0.0",
"mongoose": "^5.10.13",
"nodemon": "^2.0.6",
"react": "^17.0.1",
"react-cool-onclickoutside": "^1.5.8",
"react-dom": "^17.0.1",
"validator": "^12.0.0",
"xss-clean": "^0.1.1"
},
"devDependencies": {
"dotenv": "^8.2.0"
}
}
I could use a little help. I've deployed 5 other MERN-Stacks with a MongoDB Atlas or JawsDB connection with little to no issues and this one is just throwing me for a loop.
PLEASE HELP!!!
Everyone does things differently, but I think the error is in your connection to MongDB- are you establishing a connection OK or no?
If no connection - You said "I've added MONGOBD_URI as a key in Config Vars on Heroku and added the MongoDB Atlas value." But I see that "config Vars" is not used in your code- you used the .env as you should to keep your connection password secure...so may just need to add your connection URI to the .env file, and you are good to go?
If your connection is fine, then I would look to your server and suggest to test if the problem is solved using the standard routing:
app.route("/")
.get(function(req, res) {
res.sendFile(process.cwd() + "/views/index.html");
})

"Unexpected token stripe" when trying to deploy Firebase Functions

I'm trying to incorporate Stripe into an iOS app using Firebase Functions. I'm following the Stripe documentation for "Accepting a payment" in Swift with Node backend. I first did npm install --save stripe. That finished with no errors. Then I did npm install. My index.js looks like this so far:
// // 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 functions = require('firebase-functions');
const stripe = require('stripe')('sk_test_...');
const paymentIntent = await stripe.paymentIntents.create({
amount: 1099,
currency: 'usd',
});
const clientSecret = paymentIntent.client_secret
When running firebase deploy I get: 11:29 error Parsing error: Unexpected token stripe. Line 11 char 29 in my file is the stripe.paymentIntents...
This is my first time using Firebase Functions or Stripe, so I'm at a loss here. I appreciate any help.
EDIT:
Here's the contents of my package.json file.
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"lint": "eslint .",
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "8"
},
"dependencies": {
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.6.1",
"stripe": "^8.55.0"
},
"devDependencies": {
"eslint": "^5.12.0",
"eslint-plugin-promise": "^4.0.1",
"firebase-functions-test": "^0.2.0"
},
"private": true
}
This error is because on the cloud environment the stripe library is not installed before you require it.
npm install does install the dependencies but in your local environment, to install them on the Cloud Functions envirornment you need to edit the package.json file from the Cloud Function.
This to add the dependencies that it will be required by the function.
This is done by adding the dependency section to the package.json file
It will lok something like:
{
"name": "sample-name",
"version": "0.0.1",
"dependencies": {
"escape-html": "^1.0.3",
"stripe": "^8.24.0"
}
}
EDIT
With this code it works on Cloud functions:
const stripe = require('stripe')('<My Secret Key>');
exports.helloWorld = (req, res) => {
let paymentIntent = null;
paymentIntent = stripe.paymentIntents.create({
amount: 2000,
currency: 'usd',
description: 'My first payment',
});
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
Apparently the issue was the await because HTTP Cloud Functions work on a Synchronous way
I see this question is old but I ran into this exact issue and couldn't find an answer.
I had my backend functions folder nested within my overall app and I had let firebase generate some files for me, including a lint configuration. So, I ended up with two lint config files in my project total. The firebase generated one tried to enforce double quotes and the one I created tried to enforce single quotes. I ended up just deleting the generated lint config and it works fine now.