diff --git a/Server/configs/db.js b/Server/configs/db.js index 174978ca3..ba3c8b660 100644 --- a/Server/configs/db.js +++ b/Server/configs/db.js @@ -1,18 +1,15 @@ -const mongoose = require('mongoose') +const PORT = process.env.PORT || 5000; -const PORT = process.env.PORT || 5000 +const connectDbAndRunServer = async (app, db) => { + try { + await db.connect(); + app.listen(PORT, () => { + console.log(`server started on port:${PORT}`); + }); + } catch (error) { + console.log("Failed to connect to DB"); + console.error(error); + } +}; -const connectDbAndRunServer = async (app) => { - await mongoose.connect(process.env.DB_CONNECTION_STRING).then(() => { - console.log("DB connected") - // run server - app.listen(PORT, () => { - console.log(`server started on port:${PORT}`) - }) - }).catch((err) => { - console.log(err) - }) -} - - -module.exports = { connectDbAndRunServer } \ No newline at end of file +module.exports = { connectDbAndRunServer }; diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js index deaf2d8ba..dda18d8ff 100644 --- a/Server/controllers/monitorController.js +++ b/Server/controllers/monitorController.js @@ -3,13 +3,10 @@ const { getMonitorsByUserIdValidation, } = require("../validation/joi"); -// Fake database, if we have standardized DB methods we can swap out databases easily -const db = require("../db/FakeDb"); - // Gets all monitors const getAllMonitors = async (req, res) => { try { - const monitors = await db.getAllMonitors(); + const monitors = await req.db.getAllMonitors(); return res.json({ success: true, msg: "Monitors found", data: monitors }); } catch (error) { return res.status(500).json({ success: false, msg: error.message }); @@ -27,7 +24,7 @@ const getMonitorById = async (req, res) => { try { const monitorId = req.params.monitorId; - const monitor = await db.getMonitorById(monitorId); + const monitor = await req.db.getMonitorById(monitorId); return res.json({ success: true, msg: "Monitor found", data: monitor }); } catch (error) { return res.status(500).json({ success: false, msg: error.message }); @@ -45,7 +42,7 @@ const getMonitorsByUserId = async (req, res) => { try { const userId = req.params.userId; - const monitors = await db.getMonitorsByUserId(userId); + const monitors = await req.db.getMonitorsByUserId(userId); return res.json({ success: true, msg: `Monitors for user ${userId} found`, diff --git a/Server/db/FakeDb.js b/Server/db/FakeDb.js index d3b793f11..6dfa89ac9 100644 --- a/Server/db/FakeDb.js +++ b/Server/db/FakeDb.js @@ -1,7 +1,23 @@ // ************************** -// FakeDB is used to simulate the database -// If we standarize the DB methods we can swap out databases easily -// Too bad JS doesn't have interfaces, that would be nice. TypeScript anyone? +// The idea here is to provide a layer of abstraction between the database and whoever is using it. +// Instead of directly calling mongoose methods, we can call the methods on the DB object. +// If this were Typescript or Java or Golang an interface would be implemented to ensure the methods are available. +// But we do the best we can with Javascript. +// +// If the methods are consistent all we have to do to swap out one DB for another is simply change the import. +// +// Example: +// We start with the fake DB: +// +// const db = require("../db/FakeDb"); +// const monitors = await db.getAllMonitors(); +// +// And when we want to swtich to a real DB, all we have to do is swap the import +// +// const db = require("../db/MongoDb"); +// const monitors = await db.getAllMonitors(); +// +// The rest of the code is the same, as all the `db` methods are standardized. // ************************** const Monitor = require("../models/Monitor"); @@ -23,6 +39,14 @@ for (let i = 0; i < 10; i++) { ); } +const connect = async () => { + try { + await console.log("Connected to FakeDB"); + } catch (error) { + console.error(error); + } +}; + const getAllMonitors = async () => { return FAKE_MONITOR_DATA; }; @@ -49,5 +73,9 @@ const getMonitorsByUserId = async (userId) => { return userMonitors; }; -// Conisder standardizing these methods so we can swap databases easily -module.exports = { getAllMonitors, getMonitorById, getMonitorsByUserId }; +module.exports = { + connect, + getAllMonitors, + getMonitorById, + getMonitorsByUserId, +}; diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js new file mode 100644 index 000000000..3c48a448d --- /dev/null +++ b/Server/db/MongoDB.js @@ -0,0 +1,80 @@ +const Monitor = require("../models/Monitor"); +const mongoose = require("mongoose"); + +const seedDatabase = async () => { + const FAKE_MONITOR_DATA = []; + + for (let i = 0; i < 10; i++) { + FAKE_MONITOR_DATA.push( + new Monitor({ + userId: i % 2 === 0 ? 1 : 2, + name: `Monitor ${i}`, + description: `Description for Monitor ${i}`, + url: `https://monitor${i}.com`, + isActive: true, + interval: 60000, + updated_at: new Date(), + created_at: new Date(), + }) + ); + } + + for (const monitor of FAKE_MONITOR_DATA) { + await monitor.save(); + } +}; + +const connect = async () => { + try { + await mongoose.connect(process.env.DB_CONNECTION_STRING); + console.log("Connected to MongoDB"); + + const monitors = await Monitor.find(); + if (monitors.length === 0) { + console.log("Seeding database with fake data"); + await seedDatabase(); + } else { + console.log("Database already seeded"); + } + } catch (error) { + console.error("Failed to connect to MongoDB"); + throw error; + } +}; + +// Gets all monitors +const getAllMonitors = async (req, res) => { + try { + const monitors = await Monitor.find(); + return monitors; + } catch (error) { + throw error; + } +}; + +// Get a monitor by ID +const getMonitorById = async (req, res) => { + try { + const monitor = await Monitor.findById(req.params.monitorId); + return monitor; + } catch (error) { + throw error; + } +}; + +// Gets a monitor by user ID +const getMonitorsByUserId = async (req, res) => { + try { + const monitors = await Monitor.find({ userId: req.params.userId }); + return monitors; + } catch (error) { + throw error; + } +}; + +module.exports = { + connect, + getAllMonitors, + getMonitorById, + getMonitorsByUserId, +}; diff --git a/Server/index.js b/Server/index.js index 3913d1a58..c8136c2d0 100644 --- a/Server/index.js +++ b/Server/index.js @@ -3,10 +3,23 @@ const helmet = require("helmet"); const cors = require("cors"); const authRouter = require("./routes/authRoute"); const monitorRouter = require("./routes/monitorRoute"); -const { connectDbAndRunServer } = require("./configs/db"); +const { connectDbAndRunServer, connectViaInterface } = require("./configs/db"); require("dotenv").config(); // const { sendEmail } = require('./utils/sendEmail') +// ************************** +// Here is where we can swap out DBs easily. Spin up a mongoDB instance and try it out. +// Simply comment out the FakeDB and uncomment the MongoDB or vice versa. +// We can easily swap between any type of data source as long as the methods are implemented +// +// FakeDB +// const db = require("./db/FakeDb"); +// +// MongoDB +const db = require("./db/MongoDB"); +// +// ************************** + /** * NOTES * Email Service will be added @@ -23,6 +36,16 @@ app.use( app.use(express.json()); app.use(helmet()); +// ************************** +// Make DB accessible anywhere we have a Request object +// By adding the DB to the request object, we can access it in any route +// Thus we do not need to import it in every route file, and we can easily swap out DBs as there is only one place to change it +// ************************** +app.use((req, res, next) => { + req.db = db; + next(); +}); + //routes app.use("/api/v1/auth", authRouter); @@ -43,4 +66,4 @@ app.use("/api/v1/healthy", (req, res) => { } }); -connectDbAndRunServer(app); +connectDbAndRunServer(app, db); diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js index 7c6767364..e12982905 100644 --- a/Server/routes/monitorRoute.js +++ b/Server/routes/monitorRoute.js @@ -1,6 +1,5 @@ const router = require("express").Router(); const monitorController = require("../controllers/monitorController"); - router.get("/", monitorController.getAllMonitors); router.get("/:monitorId", monitorController.getMonitorById); router.get("/user/:userId", monitorController.getMonitorsByUserId);