Question about Environment/ Config Vars- Heroku and Postgres - node.js

Ive managed to slowly grind my way through the curriculum and just completed the backend portion.
I decided to look into building some practice project using Heroku…
If this is not the place to post his please let me know.
While following this tutorial https://devcenter.heroku.com/articles/getting-started-with-nodejs, I get to the portion where we connect to the Postgres server (‘Provision a database’). I do this successfully but I get side tracked on figuring out how to access/use this Postgres database locally when it is located and provided through Heroku. Please consider the following two methods:
Method #1
const cool = require("cool-ascii-faces");
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("/db", async (req, res) => {
try {
const client = await pool.connect();
const result = await client.query("SELECT * FROM test_table");
const results = { results: result ? result.rows : null };
res.render("pages/db", results);
client.release();
} catch (err) {
console.error(err);
res.send("Error " + err);
}
})
.get("/cool", (req, res) => res.send(cool()))
.get("/times", (req, res) => res.send(showTimes()))
.listen(PORT, () => console.log(`Listening on ${PORT}`));
const showTimes = () => {
let result = "";
const times = process.env.TIMES || 5;
for (i = 0; i < times; i++) {
console.log(i);
result += i + " ";
}
return result;
};
result form method #1
Method #2
Exactly the same code from Method #1 except I take the following steps prior to running:
Kill and reopen terminal at file location (/node-js-getting-started)> Using the credentials information (User, Password, Host, Port, and Database) in the heroku datastore resources tab I run the following in order:
% export DATABASE_URL=postgres://User:Password#Host:Port/Database
% heroku local web <--This runs app # localhost:5000
results from method #2
My question is, why does the one connect and the other doesn’t?

Related

Express app failing to connect without errors

I have been trying to connect my express app, but for some reason it is just not connecting.
I am going to "IP:PORT" on chrome and I get a typical "Refused to connect" error.
I am using node.js, and the latest version of express.
"Received" does not print to the console, however it logs "App listening on port 8088"
I have tried a lot of things, hosting on digital ocean, no connection. I am currently trying it in VSC (Ip address is my ipv4 address)
When trying using HTTP, I get a connect fail error.
My code:
const express = require('express');
const app = express()
app.use(express.json())
const fs = require('fs');
require('dotenv').config()
const serverKey = process.env.SERVER_KEY
const port = process.env.PORT
function randomString(length, chars) {
var result = '';
for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
return result;
}
module.exports = {
async execute(client) {
console.log('Test')
app.post("/getVerificationCode", function (req, res, next) {
console.log("Recieved")
if (req.body.serverKey !== serverKey) {
console.log("Invalid serverKey supplied.")
return res.status(403).json({
error: "You do not have permission to use this."
})
}
let verificationCode = randomString(4, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ').toUpperCase()
const userID = parseInt(req.body.userid)
console.log(verificationCode)
client.verificationCodes[userID] = {
code: verificationCode
}
fs.writeFile("./codes.json", JSON.stringify(client.verificationCodes, null, 4), err => {
if (err) throw err
})
return res.status(200).json({
VerificationCode: verificationCode
})
})
app.get("/*", function (req, res, next) {
return res.status(200).json({})
})
app.listen(port)
console.log(`App listening on port ${port}`)
}
}
"Test" does log, so the module IS being required. Before, I was trying it in my server.js, but that did not work and the code was messy, so I moved it into a folder.
I would really appreciate some help, thank you!

nextJS / NodeJS keeps triggering ip_ban

So not sure why, but my nodeJS / NextJS app keeps triggering plesks ip_ban. I recoded our site and moved it away from ReactJS to NextJS. But seems by doing so their must be a command that is making it look like an IP address is trying to connect to many times which makes the plesk server add the IP to a ban list (the rule that keeps getting triggered is - recidive).
I am wondering what is the correct way to solve this issue. Disabling ip_ban is a temp solution but not the ideal solution.
my server.js script is very clear and has no issues (once ip_ban is disabled).
const { createServer } = require("http");
const { parse } = require("url");
const next = require("next");
const dev = process.env.NODE_ENV !== "production";
const port = !dev ? process.env.PORT : 3000;
// Create the Express-Next App
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true);
const { pathname, query } = parsedUrl;
handle(req, res, parsedUrl);
console.log("pathname", pathname);
}).listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://example.com:${port}`);
});
})
.catch((ex) => {
console.error(ex.stack);
process.exit(1);
});
The rule that keeps getting triggered:
[recidive]
enabled = true
filter = recidive
action = iptables-allports[name=recidive]
logpath = /var/log/fail2ban.log
maxretry = 3

Make post request to Mongodb Atlas using Nodejs

I was familiar with MongodB for CRUD operation. Here, I'm trying to make simple post request on mongodB atlas but I want to know where I have done error for the connection and posting data to MongodB atlas.
Model.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
let quizSchema = new Schema({
title: {
type: String,
},
description: {
type: Number,
},
question: {
type: String,
},
});
const Quiz = mongoose.model("Quiz", quizSchema);
module.exports = Quiz;
index.js
I'm trying to create the database collection name "QuizDatabase" and insert the data to it.
var express = require("express");
var bodyParser = require("body-parser");
const Quiz = require("./views/model/model");
var Request = require("request");
var app = express();
app.use(bodyParser.json());
const MongoClient = require("mongodb").MongoClient;
const uri =
"mongodb+srv://username:password#cluster0.iom1t.mongodb.net/QuizDatabase?retryWrites=true&w=majority";
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
mongoose.connect(uri);
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
app.post("/new/", function (req, res) {
Quiz.collection("QuizDatabase").insertMany(req.body, function (err, doc) {
if (err) {
handleError(res, err.message, "Failed to create new quiz.");
} else {
res.status(201).send(JSON.stringify(body));
}
});
});
function handleError(res, reason, message, code) {
console.log("ERROR: " + reason);
res.status(code || 500).json({ error: message });
}
You dont have to use mongo client if you are already using mongoose.
In index.js file just import the model
const Quiz = require("./model");
And you are already using mongoose to connect to db when you write mongoose.connect(uri); You don't have to use client.connect() again.
Query to insert -
Quiz.insertMany(req.body);
Your index file should look like this -
const Quiz = require("./views/model/model");
var Request = require("request");
var app = express();
app.use(bodyParser.json());
const uri =
"mongodb+srv://username:password#cluster0.iom1t.mongodb.net/QuizDatabase?retryWrites=true&w=majority";
mongoose.connect(uri);
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
app.post("/new/", function (req, res) {
Quiz.insertMany(req.body, function (err, doc) {
if (err) {
handleError(res, err.message, "Failed to create new quiz.");
} else {
res.status(201).send(JSON.stringify(body));
}
});
});
function handleError(res, reason, message, code) {
console.log("ERROR: " + reason);
res.status(code || 500).json({ error: message });
}
There are several reasons.
Connection Issues to the MongoDB database.
To check this insert app.listen() into mongoose connect. This would make sure you can only run development on your preferred PORT only when it has successfully connected to your Database. e.g From your code
mongoose.connect(uri)
.then(() => {
//listen for PORT request
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
}).catch((error) => {
console.log(error);
});
Try purposely using the wrong Username or Password and see if you get this error:
MongoServerError: bad auth : Authentication failed.
at Connection.onMessage (/Users/user/Documents/..<pathway>../connection.js:207:30)
*
*
*
*
ok: 0,
code: 8000,
codeName: 'AtlasError',
[Symbol(errorLabels)]: Set(1) { 'HandshakeError' } }
If you don't get this error then you have a connection problem. To solve this, I added my current IP ADDRESS and 0.0.0.0/0 (includes your current IP address) at the Network Access page. So you click on MY CURRENT IP ADDRESS and confirm upon setting up the network. Go to NETWORK ACCESS, click on add new IP ADDRESS, input 0.0.0.0/0 and confirm. Then try using the wrong username or password in the URI link given to you to see if it gives the above-expected error, then you can now correct the Username and Password, and npm run dev or npm start (However you configured it in your package.json file).
Code issues
First of I would correct your Model.js file from this:
const Quiz = mongoose.model("Quiz", quizSchema);
module.exports = Quiz;
to this:
module.exports = mongoose.model("Quiz", quizSchema);
I can see why yours can work, but it may be an issue as you want to get the schema upon accessing the whole file.
Secondly, I would correct the code for Posting and you can do that in 2 ways using the asynchronous method. Which depends on the method of assigning the req.body.
Way 1:
app.post("/new/", async (req, res) => {
const { title, description, question } = req.body;
//adds doc to db
try {
const quiz = await Quiz.create({ title, description, question });
res.status(200).json(quiz);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
OR
Way2:
app.post("/new/", async (req, res) => {
const quiz = new Quiz(req.body);
//adds doc to db
try {
const savePost = await quiz.save();
response.status(200).send(savePost);
} catch (error) {
response.status(400).send(error);
}
});
NOTE: You don't necessarily have to create a named database and collection in Mongo Atlas before starting the project. The URI given to you covers that if there are no problems with the connection to the DB or the Code.
based on your code
URI:
"mongodb+srv://username:password#cluster0.iom1t.mongodb.net/QuizDatabase?retryWrites=true&w=majority";
would create a database called: QuizDatabase and collection called: quizs (MongoDb always creates the plural word from the model given and makes it start with lowercase (i.e from your Model.js, the mongoose.model("Quiz"))).
If no database is named in your URI, then a database called test is automatically created for you as a default database, with the collection name being the mongoose.model("") given.
CONCLUSION
This should solve at least 90% of your issues, any other creation/POST problems is currently beyond my current expertise. Happy Coding 🚀🚀🚀

how to use the connection.db.collection function?

I have implemented the following code from this link:
What is best way to handle global connection of Mongodb in NodeJs
to create a class for the connection of MongoDB. But when I try to call the singleton class in the router, I get the following error:
TypeError: Connection.db.collection is not a function
mongodb.js
const MongoClient = require('mongodb').MongoClient
const url = '...';
class Connection {
static connectToDB() {
if ( this.database ) return Promise.resolve(this.database)
return MongoClient.connect(this.url, {useNewUrlParser: true}, (err, db) => {
if (err) console.log(err);
else {
this.db = db;
console.log('MongoDB connected');
}
})
}
}
Connection.db = null
Connection.url = url
Connection.options = {
bufferMaxEntries: 0,
reconnectTries: 5000,
}
module.exports = Connection;
app.js
const express = require('express');
const app = express();
let bodyParser = require('body-parser')
// mongodb config
const Connection = require('../config/mongodb');
const server = app.listen(3000, () => {
Connection.connectToDB(); // output: MongoDB connected
console.log(`listening to port: ${port} on http://127.0.0.1:3000}/`); // output: listening to port: 3000 on http://127.0.0.1:3000/
});
router.js
const router = require('express').Router();
let Connection = require('../config/mongodb');
router.post('/data', (req, res) => {
Connection.db.collection('tweets').find({}) // output: TypeError: Connection.db.collection is not a function
.then(tweets => console.log(tweets))
.catch(err => console.log(err));
});
Try once to package.json, change mongodb line to "mongodb": "^2.2.33". You will need to npm uninstall mongodb; then npm install to install this version.
The question you linked uses promises throughout, whereas you're using the callback version of connect.
return MongoClient.connect(this.url, {useNewUrlParser: true}, (err, db) => ...
You then call this without returning in your server:
Connection.connectToDB();
console.log(`listening to port: ${port} on http://127.0.0.1:3000}/`);
There is therefore no guarantee that your connection will have been made by the time your first api request comes in. In fact, if you did:
Connection.connectToDB();
console.log(`listening to port: ${port} on http://127.0.0.1:3000}/`);
Connection.db.collection('tweets').find({});
It would fail every time as Connection.db will still be null.
In the example you linked, using Promises protect against that. Note in particular the connect method:
static connectToDB() {
if ( this.database ) return Promise.resolve(this.database)
// ** USING THE PROMISE VERSION OF CONNECT **
return MongoClient.connect(this.url, this.options)
.then(db => this.db = db)
}
and your usage code should also use promises:
return Connection.connectToDB()
.then(() => {
// do something here
});

Why does my Node application keep sending data after every refresh?

I am using node.js and express.js to build a very simple application. I want to read the content of a directory and when I browse to localhost:3000/names, the application will print an array of the content to the web page except for the content that I choose not to. Here is my code:
const express = require('express');
const fs = require('fs');
const app = express();
const port = 3000;
let result = [];
app.get('/names', (req, res) => {
const printNames = (err, file) => {
file.forEach(e => {
if (e !== 'john') {
result.push(e);
}
});
res.send(result);
};
fs.readdir('./home', printNames);
});
app.listen(port, () => {
console.log('Listening on port 3000');
});
The application works the way that I wanted to, but there is a small bug. Every time I refresh the page, the application will add on the same content of the array to the existing array. My array keeps getting bigger with every refresh. I want the application to send the array to the page and will stay the same when I refresh. I do not have the slightest idea why my application is behaving this way. Can someone explain to me why it is behaving like this and what would be the right steps to fix this?
It is because you've declared your result array in the global scope.
Your result array is getting bigger and bigger every time.
Simply move the declaration to your route and you should be fine.
This should work fine:
const express = require('express');
const fs = require('fs');
const app = express();
const port = 3000;
// let result = []; Remove this line
app.get('/names', (req, res) => {
let result = []; // And add it here
const printNames = (err, file) => {
file.forEach(e => {
if (e !== 'john') {
result.push(e);
}
});
res.send(result);
};
fs.readdir('./home', printNames);
});
app.listen(port, () => {
console.log('Listening on port 3000');
});
Read more about scopes in JavaScript here:
https://www.w3schools.com/js/js_scope.asp
Every time you request to load the page /names, it is re-running the code in that handler. If you only want to run that script once, then move it outside of the handler, and only send the result.
let result = [];
const printNames = (err, file) => {
file.forEach(e => {
if (e !== 'john') {
result.push(e);
}
});
};
fs.readdir('./home', printNames);
app.get('/names', (req, res) => {
res.send(result)
});

Resources