Please see Edit 2
I have a utils.js module that contains helper methods. Whenever other modules require it, it causes the whole app to crash. For instance, in my server.js, I have
const express = require("express");
const app = express();
const path = require("path");
const connectDb = require("./config/db");
app.use(express.json({ extended: false }));
// Define routes
app.use("/api/auth", require("./routes/api/posts"));
// connect to db
connectDb();
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Listening on port ${PORT}`));
My posts.js is:
const express = require("express");
const router = express.Router();
// model
const Post = require("../../models/Post");
const { COMMENT_SAVE_ERROR, STRING } = require("../../constants/constants");
const { sendNotification, addNotificationToDb } = require("./utils/utils");
// #route GET api/posts/test
// #desc Test route
// #access Public
router.get("/test", async (req, res) => {
console.log('reached')
});
And my connectDb method is:
const connectDb = async () => {
try {
console.log('connecting to mongodb');
await mongoose.connect(db, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true
});
console.log("Mongo DB connected");
} catch (err) {
console.log('unable to connect to mongodb');
console.log('err===> ', err);
console.log(err.message);
//exit if failure
process.exit(1);
}
};
As it is now, when I run the app, I get an error:
getaddrinfo ENOTFOUND pilled-shard-00-01-xxghh.mongodb.net
This is such a weird error, because if I get rid of this from posts.js,
const { sendNotification, addNotificationToDb } = require("./utils/utils");
It connects with no problem. What am I doing wrong here? It throws the same error if I do,
const {} = require("./utils/utils");
Is this even related to MongoDB? Am I not allowed to import functions like this?
utils.js exports the methods as,
module.exports = {
sendNotification,
addNotificationToDb
};
Edit:
const addNotificationToDb = (userId, postId, type) => {
try {
const newNotification = new Notification({
userId,
postId,
typeOfNotification: type
});
newNotification.save();
} catch (err) {
console.log("Error saving notification", err);
}
};
Edit 2:
I've figured out the culprit. api/utils.js requires models, several of which /utils/utils.js requires. So when server.js does app.use('/api/utils), those models are required twice (at least I think that's the culprit). I figured this out by commenting out the model requires in utils/utils.js. How can I circumvent this? Is my only option to require the models in api/utils and just pass them individually to the methods that are imported from utils/utils.js?
Related
Iv'e tried to use socket.io to emit data from a route file and it's crushing when i'm calling the route.
Error while getting quotes Cannot read properties of undefined (reading 'emit')
TypeError: Cannot read properties of undefined (reading 'emit')
Does anyone know why is this happens?
Thanks.
app.ts
const express = require('express');
const io = require("socket.io");
const indexRouter = require('./routes');
const quotesRouter = require('./routes/quotes');
const app = express();
const listener = app.listen(3001, () => console.log("Listening..."));
const socketsManager = io(listener, {cors: {origin: "*"}});
socketsManager.sockets.on("connection", (socket: any) => {
console.log("One client has been connected. Total clients: " + socketsManager.engine.clientsCount);
// Listen to disconnect event from the connected client:
socket.on("disconnect", () => {
console.log("A specific client has been disconnected. Total clients: " + (socketsManager.engine.clientsCount - 1));
});
socket.on("getQuotes", (quotes: Quote[]) => {
socket.emit('getQuotes', quotes);
});
});
app.set('socketio', io);
app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.use('/', indexRouter);
app.use('/quotes', quotesRouter);
module.exports = app;
quotes.ts (route file)
import {NextFunction, Request, Response} from 'express';
const app = require('../app');
const express = require('express');
const router = express.Router();
const quotes = require('../services/quotes');
router.get('/', async function (req: Request, res: Response, next: NextFunction) {
try {
let io = req.app.get('socketio');
io.sockets.emit('getQuotes',await quotes.getMultiple(req.query.page));
// res.status(200).json(await quotes.getMultiple(req.query.page));
} catch (err: any) {
console.error(`Error while getting quotes `, err.message);
next(err);
}
});
module.exports = router;
Looks like you've assigned wrong value to socketio. Instead of assigning io, you need socketsManager which is the initialized socket instance
const socketsManager = io(listener, {cors: {origin: "*"}});
So, update your socketio variable definition like this,
app.set('socketio', socketsManager);
I have created an express server in my server.js file, and I export app from it.
//server.js
require("dotenv").config();
const express = require("express");
const app = express();
const connectToDb = require("./connectToDb")
connectToDb().catch(console.dir)
app.use((req, res) => {
res.status(404).send("unable to find");
});
module.exports = app
I import app from server.js in the connectToDb.js file
//connectToDb.js
const app = require("./server")
const MongoClient = require("mongodb").MongoClient;
const client = new MongoClient(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
const port = process.env.PORT || 3000;
const connectToDb = async () =>{
try {
await client.connect();
console.log("Connected correctly to server");
app.listen(port, () => {
console.log(`Listening on port ${port}`);
})
} catch (err) {
console.log(err.stack);
} finally {
await client.close();
console.log("hello")
}
}
module.exports = connectToDb
It connects succesfully to the database, but when it reaches app.listen it gives me this error: TypeError: app.listen is not a function. I don't know why it gives me an error because I have exported app. What am I doing wrong?
That's because you have a cyclic dependency. The two files import each other, and inside server.js you make a call immediately on load. In the moment you call connectToDb inside of server.js, the server.js file has not fully executed yet and hence the module export has not yet happened. Either way it's something you should try to avoid (cyclic dependencies).
Just resolve the cycle by passing the app to the connectToDb function as a parameter instead of importing it:
//server.js
require("dotenv").config();
const express = require("express");
const app = express();
const connectToDb = require("./connectToDb")
connectToDb(app).catch(console.dir)
app.use((req, res) => {
res.status(404).send("unable to find");
});
module.exports = app
// connectToDb.js
const MongoClient = require("mongodb").MongoClient;
const client = new MongoClient(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
const port = process.env.PORT || 3000;
const connectToDb = async (app) =>{
try {
await client.connect();
console.log("Connected correctly to server");
app.listen(port, () => {
console.log(`Listening on port ${port}`);
})
} catch (err) {
console.log(err.stack);
} finally {
await client.close();
console.log("hello")
}
}
module.exports = connectToDb
I'm learning the MERN stack and creating the typical beginner "Todo" App. When I make an axios call such as axios.post("http://localhost:4000/todos/add", newTodo) it posts fine, but when I try axios.post("/todos/add", newTodo) it doesn't.
The call obviously only works locally - how do I fix this/what am I doing wrong?
Here is todos.js file located in /routes/api folder:
const todoRouter = require("express").Router();
let Todo = require('../../models/todo');
todoRouter.route("/").get(function (req,res){
Todo.find(function(err, todos){
if (err){
console.log (err)
} else {
res.json(todos)
}
});
});
todoRouter.route("/:id").get(function(req,res){
let id = req.params.id
Todo.findById(id, function(err,todo){
if (err) {
console.log(err)
} else {
res.json(todo)
}
});
});
todoRouter.route("/add").post(function(req,res){
let todo = new Todo(req.body)
todo.save()
.then(function (todo){
res.status(200).json({"todo": "todo added successfully"})
})
.catch(function (err){
res.status(400).json("adding new todo failed")
})
})
todoRouter.route('/update/:id').post(function(req, res) {
Todo.findById(req.params.id, function(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");
});
});
});
module.exports = todoRouter;
Here is my index.js located in /routes/api folder:
const router = require("express").Router();
const todoRoutes = require("./todos");
// Todo routes
router.use("/todos", todoRoutes);
module.exports = router;
Here is index.js located in the /routes folder:
const path = require("path");
const router = require("express").Router();
const todoRoutes = require("./api");
// API Routes
router.use(todoRoutes);
// If no API routes are hit, send the React app
router.use(function(req, res) {
res.sendFile(path.join(__dirname, "../client/build/index.html"));
});
module.exports = router;
Here is my server.js file:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose')
const PORT = process.env.PORT || 4000;
const routes = require('./routes')
// Define middleware here
app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Serve up static assets (usually on heroku)
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
}
// Define API Routes
app.use(routes)
// Send every other request to the React app
// Define any API routes before this runs
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "./client/build/index.html"));
});
//Connect to mongoose
mongoose.connect(process.env.MONGODB_URI || "mongodb://127.0.0.1:27017/todos", { useNewUrlParser: true });
const connection = mongoose.connection
connection.once("open", function () {
console.log("MongoDB database connection established successfully")
})
app.listen(PORT, function () {
console.log("Server is running on Port: " + PORT);
});
Just set "proxy": "http://localhost:4000" property in your package.json and all your /something requests will be directed towars your backend without having to specify the base url
you can set the baseUrl for axios to http://localhost:4000 and then relative paths should work. https://github.com/axios/axios#creating-an-instance
I am using a NextJS/MERN stack. My NextJS is using my server.js file, along with importing the routes for my API. The routes appear to be working as they do show activity when firing an API call from Postman or the browser. However, this is where the activity stops. It's not getting passed the Model.find() function as far as I can tell. I am not sure if this has to do with Next js and the prepare method in the server.js, or if this is related to the bodyparser issue.
Here is my server.js
const express = require("express");
const urlObject = require('./baseURL')
const passport = require("./nextexpress/config/passport-setup");
const passportSetup = require("./nextexpress/config/passport-setup");
const session = require("express-session");
const authRoutes = require("./nextexpress/routes/auth-routes");
const KBRoutes = require("./nextexpress/routes/kb-routes");
const userRoutes = require('./nextexpress/routes/user-routes')
const pollRoutes = require('./nextexpress/routes/poll-routes')
const mongoose = require("mongoose");
const cookieParser = require("cookie-parser"); // parse cookie header
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const nextapp = next({ dev })
const handle = nextapp.getRequestHandler()
const bodyParser = require('body-parser');
// mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/kb', { useNewUrlParser: true });
mongoose.connect('mongodb://localhost:27017/kb')
console.log(process.env.MONGODB_URI)
const connection = mongoose.connection;
const baseURL = urlObject.baseURL
const PORT = process.env.PORT || 3000
connection.once('open', function () {
console.log("MongoDB database connection established successfully");
})
nextapp.prepare().then(() => {
const app = express();
console.log(process.env.PORT, '----port here ----')
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use("/api/auth", authRoutes);
app.use("/api/kb", KBRoutes);
app.use('/api/user', userRoutes)
app.use('/api/poll', pollRoutes)
app.get('/posts/:id', (req, res) => {
return nextapp.render(req, res, '/article', { id: req.params.id })
})
app.get('/redirect/:id', (req, res) => {
return nextapp.render(req, res, '/redirect')
})
app.all('*', (req, res) => {
return handle(req, res)
})
app.listen(PORT, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${PORT}`)
})
})
// connect react to nodejs express server
And the relevant route:
KBRoutes.get('/', (req, res) => {
console.log(KB.Model)
KB.find({}, (err, photos) => {
res.json(kbs)
})
})
I am able to get to each one of the routes. Before this was working, when I had the NextJS React portion split into a separate domain therefore separate server.js files. Once I introduced NextJs thats when this problem arose. Any help would be greatly appreciated.
It looks like the relevant route is trying to return json(kbs), but kbs doesn't seem to be defined. Returning the result of your find query would make more sense to me, including a nice error catcher and some status for good practice. Catching errors should tell you what's going wrong, i would expect an error in your console anyway that would help us out finding the answer even more.
KB.find({}, (err, photos) => {
if (err) res.status(401).send(err)
res.status(200).json(photos)
})
I am creating nodejs backend app with postgresql database. What I want is when once I create connection to database in my db.js file, that I can reuse it in other files to execute queries.
This is my db.js file
const pool = new Pool({
user: 'us',
host: 'localhost',
database: 'db',
password: 'pass',
port: 5432,
})
pool.on('connect', () => {
console.log('connected to the Database');
});
module.exports = () => { return pool; }
And this is how I tried to use it in index.js file
const db = require('./db.js')
app.get('/', (request, response) => {
db().query('SELECT * FROM country'), (error, results) => {
if (error) {
response.send(error)
}
console.log(results)
response.status(201).send(results)
}
})
There aren't any errors, and when I go to this specific page, it's keep loading. Nothing in console also.
But, if I write a function in my db.js file and do something like pool.query(...), export it, and in my index.js I write app.get('/', exportedFunction), everything is working fine.
Is there any way not to write all my (like 50) queries in just one (db.js) file, because I want to organise my project a little bit?
To streamline your project structure entirely, if you're starting from scratch maybe try this :
index.js
const express = require('express');
const app = express();
const PORT = 8080;
const bodyparser = require('body-parser');
const baseRouter = require('../your-router');
app.use(bodyparser.json());
app.use(express.json());
app.use('/', baseRouter);
app.listen(PORT, function () {
console.log('Server is running on PORT:', PORT);
});
your-router.js
const Router = require('express');
const router = Router();
const getCountries = require('../handlers/get');
router.get('/check-live', (req, res) => res.sendStatus(200));
// route for getCountries
router.get('/countries', getCountries);
src/handler/get.js
const YourService = require('./service/your-service');
function getCountries(request, response) {
const yourService = new YourService();
yourService.getCountries(request)
.then((res) => { response.send(res); })
.catch((error) => { response.status(400).send({ message: error.message }) })
}
module.exports = getCountries;
src/service/your-service.js
const connectionPool = require('../util/dbConnect');
class yourService {
getCountries(req) {
return new Promise(((resolve, reject) => {
connectionPool.connect((err, db) => {
if (err) reject(err);
let query = format('SELECT * FROM country'); // get inputs from req
db.query(query, (err, result) => {
if (err) reject(err);
resolve(result);
})
});
}));
}
}
module.exports = yourService;
dbConnect.js
const pgCon = require('pg')
const PGUSER = 'USER'
const PGDATABASE = 'localhost'
let config = {
user: PGUSER,
database: PGDATABASE,
max: 10,
idleTimeoutMillis: 30000
}
let connectionPool = new pgCon.Pool(config);
module.exports = connectionPool;
Please consider this as a basic example, refactor your code to use callbacks/async awaits (in the above example you can just use callbacks not needed to convert into promise), if needed - you can have DB-layer calls from the service layer in order to extract DB methods from the service layer.