Deploying to Heroku: Env variables are undefined - node.js

Disclaimer: This is my first question so any helpful critiques on how to make future ones better is welcome. I'm also relatively new to programming and stack overflow so forgive me if I don't understand some concepts or my question is vague or not understandable.
My Problem: I am trying to deploy my MERN stack app to heroku (im using mongodb atlas) and in my heroku logs its saying that my mongodb uri is undefined instead of a string. My uri is set to an environment variable, and everything works fine on my local machine. When push my code up to heroku though, the uri is suddenly undefined. I've researched the problem and come across various solutions but none of them work. The most common solutionn was to set the env variable on heroku in the config vars section, but that doesn't work either.
Error Message: Error [MongooseError]: The `uri` parameter to `openUri()` must be a string, got "undefined". Make sure the first parameter to `mongoose.connect()` or `mongoose.createConnection()` is a string.
My Server Code:
const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose')
require('dotenv').config();
const app = express();
const port = process.env.PORT || 5000;
app.use(cors());
app.use(express.json());
const uri = process.env.ATLAS_URI;
console.log(uri)
mongoose.connect(uri, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true }
);
const connection = mongoose.connection;
connection.once('open', () => {
console.log('MongoDB database connection made, yay!')
})
const exerciseRouter = require('./routes/exercises')
app.use('/exercises', exerciseRouter);
app.listen(port, () => {
console.log(`Server is running on port ${port}`)
})
When I run this on my local machine the console.log() function prints out the correct uri and the database connection is successful but the problems still occur when I push this code to heroku.
Let me know if I should provide any more details on the problem, this was all I could think of that would be helpful. Thanks!

Related

Make sure the first parameter to `mongoose.connect()` is a string

I'm trying to connect MongoDB Atlas to my application and ran into this error when trying to run the mongoose.connect(), which is located in db.js (last code in the question). process.env.MONGO_URI seems to be interpreted as undefined and not string, giving the following error: "MongooseError: The uri parameter to openUri() must be a string, got "undefined". Make sure the first parameter to mongoose.connect() or mongoose.createConnection() is a string."
this is the my config.env, in which I copy pasted the MONGO_URI from the Atlas.
MONGO_URI = mongodb+srv://kpae:XXXX#practice.xujsvaf.mongodb.net/?retryWrites=true&w=majority
this is app.js, where I believe I set up the basics to run the program.
const express = require('express')
const dotenv = require('dotenv')
const connectDB = require('./config/db')
dotenv.config({ path: '.config/config.env' })
connectDB()
const app = express()
const PORT = process.env.PORT || 5000
app.listen(
PORT,
console.log(`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`)
)
this is db.js
const mongoose = require('mongoose')
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false
})
console.log(`MongoDB Connected: ${conn.connection.host}`)
} catch (err) {
//console.log('this is an error')
console.error(err)
process.exit(1)
}
}
module.exports = connectDB
I'm having trouble pinpointing where the bug lies in my code because it seems like my files are in the root folder and MONGO_URI looks like a string. Any help is appreciated.
Can you please try once like this in your env file?
MONGO_URI='mongodb+srv://kpae:XXXX#practice.xujsvaf.mongodb.net/?retryWrites=true&w=majority'

Why "Server is Connected" comes before the "Database is connected" in terminal of VScode in express app?

I just want to know Why "Server is Connected" comes before the "Database is connected" in terminal of VScode in express app?
Here is my code
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const exercises = require("./routes/exercises");
const users = require("./routes/users");
require('dotenv').config();
const app = express();
const port = process.env.PORT || 8000;
app.use(cors());
app.use(express.json());
mongoose.connect("mongodb+srv://#cluster0.lzvul.mongodb.net/my_database?retryWrites=true&w=majority&useNewUrlParser=true&useUnifiedTopology=true");
const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error: "));
db.once("open", () => {
console.log("Connected successfully");
});
app.listen(port , () => {
console.log(`Server is running on localhost:${port}`);
})
First, take care of your credentials, use the .env file just like you used it for storing the port.
Now, talking about what happened to your code.
The mongoose.connection function returns a Promise, which means, a peace of code that will run along side the rest of your code if you don't specify that you want to wait for it to respond back.
For this reason, the server starts running before the database is properly connected, it takes longer for your application to get in contact with mongodb servers than it takes for express to get running.
I strongly recommend you to have a look at the Promise documentation to understand it deeper.
Anyway a possible solution for know is to await for the mongoose connection to be stablished and just then start your server
...
/*
Assuming you've put your mongodb URI in the MONGO_URI variable
at the .env file
*/
mongoose.connect(process.env.MONGO_URI)
.then(() => {
const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error: "));
db.once("open", () => {
console.log("Connected successfully");
});
app.listen(port , () => {
console.log(`Server is running on localhost:${port}`);
});
})
.catch((err) => {
console.log("Something went wrong with the database connection");
});
By using the .then method we are basically saying, we want to wait for this function to respond, and when it responds we want to execute this following function, where we call the rest of logic you wrote, server startup included.
That will make sure that the database initializes before the server and if something goes wrong with this process the server doesn't start.

How can I connect my local node.js app to my Heroku Postgres database?

I've managed to get my Node.js app working properly with my Heroku Postgres database when the node application is deployed to Heroku. However having to deploy to heroku each time I make a code change is a bit arduous and I'd rather be able to develop locally and connect to the database from my local app.
https://devcenter.heroku.com/articles/connecting-to-heroku-postgres-databases-from-outside-of-heroku
The above article doesn't really describe how this is done, I'm not exactly sure what I need to do.
If I attempt to run my app locally and access an endpoint that queries my database I get
Error Error: connect ECONNREFUSED 127.0.0.1:5432
Whereas if I access the same endpoint from my heroku deployed app it works correctly.
Here's my app
const express = require('express')
const path = require('path')
const PORT = process.env.PORT || 5000;
const { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
}
});
express()
.use(express.static(path.join(__dirname, 'public')))
.set('views', path.join(__dirname, 'views'))
.set('view engine', 'ejs')
.get('/', (req, res) => res.render('pages/index'))
.get('/users', async (req, res) => {
try {
const client = await pool.connect();
const result = await client.query('SELECT * FROM users');
const results = { 'results': (result) ? result.rows : null};
console.log(results);
res.status(200).json(results);
} catch (err) {
console.error(err);
res.send("Error " + err);
}
})
.listen(PORT, () => console.log(`Listening on ${ PORT }`));
I think you need to update the the process.env.DATABASE_URL on your local machine. From the error, it looks like the DATABASE_URL refers to localhost while you want to use the db hosted on Heroku.
I understand that you only want to use the remote db only. The error says you're unable to connect to 127.0.0.1:5432. This is the IP address of localhost, not the remote database. Your code is trying to connect to 127.0.0.1:5432 for some reason while it should be trying to connect to the remote db.
Did you use the dotenv to access process.env.DATABASE_URL ?
You need dotenv.config(); worked for me.

Server doesn't start

Today I try open my server, but it doesn't start
Full code - https://github.com/meln1337/error-proxy
app.js
const express = require('express')
const config = require('config')
const mongoose = require('mongoose')
const app = express()
app.use(express.json({extended: true}))
app.use('/api/auth', require('./routes/auth.routes'))
const PORT = config.get('port') || 5000
async function start () {
try {
await mongoose.connect('mongodb+srv://borys:1q2w3e4r5t6y7u8i#cluster0-puuhz.mongodb.net/app', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
})
app.listen(PORT, () => {
console.log(`App has been started on port ${PORT}...`)
})
} catch (e) {
console.log('Server error', e.message)
process.exit(1)
}
}
start()
config/default.json
{
"port": 5000
}
Does the server not start due to mongodb?
If not then why does the server not start?
I was able to run it, locally, with a few changes to "remove" missing files (i.e., changing your mongodb uri to a localhost thingy).
Have you checked your console? When I run it, I get (assuming I have config), TypeError: config.get is not a function. So unless I'm missing something, that's your first issue.
The second is that, for me, obviously the Mongodb instance won't work. I assume that's not true for you - you don't get error querySrv ENODATA - but that's worth checking too.
Finally, if your question is still about mongodb, why not remove that? Just comment out the await... bit, and see if the server starts?

How to load mongodb URI from .env file on heroku?

I am a beginner to MERN stack and I deployed my nodejs app to heroku but the app is unable to connect to mongodb atlas and data from the database does not load when I give the mongodb uri via an environment variable.It works fine when I directly give the uri via a variable.Also when run locally,the app connects to atlas without any problem using environment variable.Any idea why its not working on heroku and how to fix it?
server.js
const express = require('express'); //nodejs framework for creating web apps
const cors = require('cors');
const mongoose = require('mongoose');
const path = require('path');
require('dotenv').config(); //for setting environment variables on server
const app = express(); //creating the app
//Serve static assets if in production
if(process.env.NODE_ENV ==='production'){
//Set static folder
app.use(express.static('client/build'));
app.get('*',(req, res) => {
res.sendFile(path.resolve(__dirname,'client','build','index.html'));
});
}
////////////////////////////////////////
const port = process.env.PORT || 5000;
app.use(cors()); //for cross origin resource sharing ie.cross domain requests
app.use(express.json()); //for handling json data
const uri = process.env.ATLAS_URI;
//its works fine when I give it as below
//const uri="mongodb+srv://jose:<password>#exercisecluster-rmqkg.gcp.mongodb.net/test?retryWrites=true&w=majority"
mongoose.connect(uri,{ useNewUrlParser: true, useCreateIndex: true ,useUnifiedTopology: true });
const connection = mongoose.connection;
connection.once('open',() => {
console.log('Database connection established successfully');
})
const exercisesRouter = require('./routes/exercises');
const usersRouter = require('./routes/users');
//executes the files in the second argument when user enters the url 'rooturl/firstargument'
app.use('/exercises',exercisesRouter);
app.use('/users',usersRouter);
app.listen(port,() => {
console.log(`Server is running on port:${port}`);
});
In your heroku project you need to setup an env variable ATLAS_URI and enter the value for your mongodb uri.
To do so go to the settings tab in your heroku app, then click on reveal config vars, and then enter the key and value for your mongo uri.
Hope this helps

Resources