Error when combining Express Router with Massive.js db call - postgresql

When making an async/await call to database from an express router to postgres db via massive.js instance, the correct response from db is received, but the router apparently returns before async function finishes; therefore, the test invocation returns undefined. From the console out (below), it seems clear that the async function is not waited for >_<
Is wrapping the router in order to pass the app instance causing the issue?
app.js
const app = express();
const massiveInstance = require("./db_connect");
const routes = require("./routes");
const PORT = 3001;
const server = massiveInstance.then(db => {
// Add db into our app object
app.set("db", db);
app.use("/api", routes(app));
app.listen(PORT, () => {
console.log("Server listening on " + PORT);
});
});
routes.js
const router = require("express").Router();
const { countRegions } = require("./db_queries");
const routes = app => {
const db = app.get("db");
router.get("/regions/count", async (request, response) => {
try {
const total = await countRegions(db);
console.log(`There are ${total} regions.`);
response.send(`There are ${total} regions.`);
} catch (err) {
console.error(err);
}
});
return router;
};
module.exports = routes;
db_queries.js
const countRegions = db => {
db.regions.count().then(total => {
console.log(`db has ${total} count for regions`);
return total;
});
};
module.exports = {
countRegions,
};
console output
Server listening on 3001
There are undefined regions.
db has 15 count for regions

You are not returning a promise returned by then in countRegions method.
So you should add return in your code like this
const countRegions = db => {
//here
return db.regions.count().then(total => {
console.log(`db has ${total} count for regions`);
return total;
});
};
or simply do,
return db.regions.count();

Related

Error: connect ECONNREFUSED 127.0.0.1:8000 in Express Js ( When try to Test with Postman )

I am really new to the industry and have this error when trying to check the database connection via API reuests with postman..... Please help me to settle this issue...
I just want to check the mongodb database by sendng API requests. Still I cannot identify the error and I am following a set of tutorials and occure this issue... Anyone can help me to identify the mistake it's highly appreciated....
{ this is dummy text to avoid please add more details...
Here is my code...
const app = express();
const { MongoClient } = require('mongodb');
const PORT = process.env.PORT || 8000;
// Initialize middleware
// we used to install body parser but now it's a built in middleware
// Function of express. It parses incoming JSONpayload
// app.use(express.json({extended:false}));
app.use(express.json({ extended: false }));
// Test Routs
// app.get("/", (req,res)=>res.send("Hello Aruna !!!"));
// app.post("/", (req,res)=>res.send(`Hello ${req.body.name} `));
// app.get("/hello/:name", (req.res)=>res.send(`Hello ${req.params.name}`))
app.get('/api/articles/:name', async (req, res) => {
try {
const articleName = req.params.name;
const client = await MongoClient.connect('mongodb://localhost:27017');
const db = client.db('mernblog');
const articlesinfo = db
.collection('articles')
.findOne({ name: articleName });
res.status(200).jason(articlesinfo);
client.close();
} catch (error) {
res.status(500).jason({ message: 'Error connecting to database', error });
}
});
app.post('/api/articles/:name/add-comments', (req, res) => {
const { username, text } = req.body;
const articleName = req.params.name;
articlesinfo[articleName].comments.push({ username, text });
res.status(200).send(articlesinfo[articleName]);
});
app.post('/', (req, res) => res.send(`Hello ${req.body.name}`));
app.get('/hello/:name', (req, res) => res.send(`Hello ${req.params.name}`));
app.listen(PORT, () => console.log(`Server is running at port ${PORT}`));
Server.js
Terminal
Error and API request in Postman
You have a typo in your code: jason should be json.
Other tips, you should handle your DB connection in a separate method and change your post request since articlesinfo is not a global variable:
const app = express();
const { MongoClient } = require('mongodb');
const PORT = process.env.PORT || 8000;
const client = new MongoClient('mongodb://localhost:27017');
const connectDB = async () => {
try {
await client.connect();
console.log('Successfully connected to DB')
} catch (err) {
await client.close();
console.log('Error connecting to DB');
process.exit(1);
}
}
// Initialize middleware
// we used to install body parser but now it's a built in middleware
// Function of express. It parses incoming JSONpayload
// app.use(express.json({extended:false}));
app.use(express.json({ extended: false }));
// Test Routs
// app.get("/", (req,res)=>res.send("Hello Aruna !!!"));
// app.post("/", (req,res)=>res.send(`Hello ${req.body.name} `));
// app.get("/hello/:name", (req.res)=>res.send(`Hello ${req.params.name}`))
app.get('/api/articles/:name', async (req, res) => {
try {
const articleName = req.params.name;
const db = client.db('mernblog');
const articlesinfo = db
.collection('articles')
.findOne({ name: articleName });
res.status(200).json(articlesinfo);
client.close();
} catch (error) {
res.status(500).json({ message: 'Error connecting to database', error });
}
});
app.post('/api/articles/:name/add-comments', (req, res) => {
const { username, text } = req.body;
const articleName = req.params.name;
const db = client.db('mernblog');
const articlesinfo = db
.collection('articles')
.updateOne({ name: articleName }, { $push: { comments: { username, text } } });
res.status(200).send(articlesinfo);
});
app.post('/', (req, res) => res.send(`Hello ${req.body.name}`));
app.get('/hello/:name', (req, res) => res.send(`Hello ${req.params.name}`));
connectDB();
app.listen(PORT, () => console.log(`Server is running at port ${PORT}`));

Mongo DB Runtime Error because of connection is closed too early

I had the same issue with the below question, and the answer(adding setTimeout()) worked for me.
MongoRuntimeError: Connection pool closed
But I can't find more information about this issue on any other documents, Youtube video, or MongoDB Guide. All of them close the connection without setTimeout function. Am I missing something? or if there is a better way to close the connection. Please advise.
const { MongoClient } = require("mongodb");
const url =
"mongodb+srv://USERNAME:PASSWORD#cluster0.feify.mongodb.net/products_test?retryWrites=true&w=majority";
const createProduct = async (req, res, next) => {
const newProduct = {
name: req.body.name,
price: req.body.price,
};
const client = new MongoClient(url);
try {
await client.connect();
const db = client.db();
const result = db.collection("products").insertOne(newProduct);
} catch (error) {
return res.json({ message: "Could not store data." });
}
setTimeout(() => {
client.close();
}, 1500);
res.json(newProduct);
};
const getProducts = async (req, res, next) => {};
exports.createProduct = createProduct;
exports.getProducts = getProducts;
Thank you
You should await the insertOne function:
const { MongoClient } = require("mongodb");
const url =
"mongodb+srv://USERNAME:PASSWORD#cluster0.feify.mongodb.net/products_test?retryWrites=true&w=majority";
const createProduct = async (req, res, next) => {
const newProduct = {
name: req.body.name,
price: req.body.price,
};
const client = new MongoClient(url);
try {
await client.connect();
const db = client.db();
const collection = db.collection("products");
const result = await collection.insertOne(newProduct);
} catch (error) {
return res.json({ message: "Could not store data." });
}
client.close();
res.json(newProduct);
};
const getProducts = async (req, res, next) => {};
exports.createProduct = createProduct;
exports.getProducts = getProducts;

Express and MongoDB without Mongoose

This is not so much of a question but more of a consult request. I couldn't find resources to check my method's validity so I would like to hear MongoDB experts' opinion.
I was playing around with MongoDB and came up with this middleware method to pass client to my routes. I have this Express middleware:
const addClientToRequest = async (req, _, next) => {
const client = new MongoClient(uri);
await client.connect();
req.client = client;
next();
};
app.use(addClientToRequest);
After that, I use req.client in my routes to access my database.
app.get("/:id", async (req, res) => {
const client = req.client;
const id = req.params.id;
try {
const data = await client.db("mydb").collection("mycollection").findOne({ id });
if (data) return res.status(200).json(data);
} catch (error) {
return res
.status(500)
.json({ message: "Error fetching requested data", error });
}
return res.status(404).json({ message: "Requested data cannot be found" });
});
What would be a problem in this approach? Is it okay to use MongoDB client like this?
In my experience, we have always defined a separate utility to load a connection pool at the app startup and then reused those connections.
In the above approach, you seem to be creating a new connection for every HTTP request that is made and then not terminating (or) closing the connection. This may be expensive for a large app.
db.util.js
const { MongoClient } = require("mongodb");
const uri = `mongodb://${process.env.DB_USER}:${process.env.DB_PASSWORD}#localhost:27017/${process.env.DATABASE}?maxPoolSize=2-&w=majority`;
const client = new MongoClient(uri);
const init = async () => {
try {
await client.connect();
console.log("Connected");
} catch (error) {
console.log(error);
}
};
const getClient = () => {
return client;
};
module.exports.init = init;
module.exports.getClient = getClient;
app.js
//Import modules
require("dotenv").config({ path: __dirname + "/.env" });
const express = require("express");
const dogRoutes = require("./routes/dog.routes");
const db = require("./utils/db.util");
// Define PORT for HTTP Server
const PORT = 9900;
// Initialize Express
const app = express();
app.use(express.json());
app.use(dogRoutes);
(async () => {
await db.init();
app.listen(PORT, (err) => {
console.log(`Server is up at localhost ${PORT}`);
});
})();
I think that what you could do is to put the client outside of the middleware, so you doesn't re define it and re connect to it each time a request is done.
To do so, simply define it and connect before the middleware, and in the middleware, set the client as req.mongoClient or how you want to name it.
const client = new MongoClient(uri);
await client.connect(); // if this is outside of an async function, either use an async function like (async () => {..script..})(), either define a variable isClientReady and set it on true after the promise resolved.
const addClientToRequest = (req, _, next) => {
req.client = client;
next();
};
app.use(addClientToRequest);

mongodb client not connecting in jest test

I am trying to setup an integration test for apollo graphql and need to connect to my mongodb database but this doesnt seem to be working. See the below code:
const MongoClient = require('mongodb').MongoClient
const LOADER_URI = 'mongodb://localhost:27017'
describe('ApolloIntegrationTest', () => {
test('Test', () => {
MongoClient.connect(URI, (err, client) => {
if(err) throw err
const pulseCore = client.db('pulse-core')
console.log(pulseCore)
const books = pulseCore.collection('books')
console.log(books)
client.close()
})
})
});
When i run the test, i expected to see the console logs printing but nothing prints when the test finishes. Not sure what i am doing wrong here.
You can use beforeAll and afterAll to simplify this.
const MongoClient = require('mongodb').MongoClient;
const LOADER_URI = 'mongodb://localhost:27017'
describe('ApolloIntegrationTest', () => {
let connection;
beforeAll(async () => {
connection = await MongoClient.connect(LOADER_URI);
});
afterAll(async () => {
await connection.close();
});
test('Test', async () => {
const pulseCore = await connection.db('pulse-core');
console.log(pulseCore);
const books = pulseCore.collection('books');
console.log(books);
});
});

Connect Apollo with mongodb

I want to connect my Apollo server with my mongoDB. I know there are many examples out there, but I get stuck at the async part and did not found a solution or example for that (that's strange, am I completly wrong?)
I started with the example from next.js https://github.com/zeit/next.js/tree/master/examples/api-routes-apollo-server-and-client .
But the mongodb integration is missing.
My code
pages/api/graphql.js
import {ApolloServer} from 'apollo-server-micro';
import {schema} from '../../apollo/schema';
const apolloServer = new ApolloServer({schema});
export const config = {
api: {
bodyParser: false
}
};
export default apolloServer.createHandler({path: '/api/graphql'});
apollo/schema.js
import {makeExecutableSchema} from 'graphql-tools';
import {typeDefs} from './type-defs';
import {resolvers} from './resolvers';
export const schema = makeExecutableSchema({
typeDefs,
resolvers
});
apollo/resolvers.js
const Items = require('./connector').Items;
export const resolvers = {
Query: {
item: async (_parent, args) => {
const {id} = args;
const item = await Items.findOne(objectId(id));
return item;
},
...
}
}
apollo/connector.js
require('dotenv').config();
const MongoClient = require('mongodb').MongoClient;
const password = process.env.MONGO_PASSWORD;
const username = process.env.MONGO_USER;
const uri = `mongodb+srv://${username}:${password}#example.com`;
const client = await MongoClient.connect(uri);
const db = await client.db('databaseName')
const Items = db.collection('items')
module.exports = {Items}
So the problem is the await in connector.js. I have no idea how to call this in an async function or how to provide the MongoClient on an other way to the resolver. If I just remove the await, it returns – obviously – an pending promise and can't call the function .db('databaseName') on it.
Unfortunately, we're still a ways off from having top-level await.
You can delay running the rest of your code until the Promise resolves by putting it inside the then callback of the Promise.
async function getDb () {
const client = await MongoClient.connect(uri)
return client.db('databaseName')
}
getDb()
.then(db => {
const apollo = new ApolloServer({
schema,
context: { db },
})
apollo.listen()
})
.catch(e => {
// handle any errors
})
Alternatively, you can create your connection the first time you need it and just cache it:
let db
const apollo = new ApolloServer({
schema,
context: async () => {
if (!db) {
try {
const client = await MongoClient.connect(uri)
db = await client.db('databaseName')
catch (e) {
// handle any errors
}
}
return { db }
},
})
apollo.listen()