diff --git a/.env.example b/.env.example index f06b31b..8e7cb17 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,3 @@ PORT=8080 -DATABASE_CONNECTION_STRING="PUT YOUR DATABASE CONNECTION STRING HERE" \ No newline at end of file +DATABASE_CONNECTION_STRING="" +MONGO_DB_NAME="example_db" # REPLACE THIS WITH A RELEVANT NAME FOR YOUR PROJECT \ No newline at end of file diff --git a/README.md b/README.md index e2d42a9..552ab6b 100644 --- a/README.md +++ b/README.md @@ -56,21 +56,27 @@ Read the `server/` [README](./server/README.md) for more details of the example We have provided you with an example environment variables file called [`.env.example`](./.env.example). Rename this file to `.env` to use it. -In here you should assign your database connection string to the `DATABASE_CONNECTION_STRING` variable. +In here, you should copy your database connection string (which you can get from the MongoDB Atlas site or the MongoDB extension in VS Code) to the `DATABASE_CONNECTION_STRING` variable. -Make sure your connection string has the correct database name you are trying to connect to and follows this format: +Make sure your connection string follows this format: ```plain -mongodb+srv://:@cluster0.7k5er.mongodb.net/ +mongodb+srv://:@.mongodb.net ``` -For the example app the database name is `example_db`. +If your connection string has a database name appended as below, remove it: + +```plain +mongodb+srv://:@.mongodb.net/ +``` + +For the example app, the database name is `example_db`. You'll also see the `PORT` for your API in this file. Do not change this `PORT` number. 🛑 **YOUR ENVIRONMENT VARIABLES SHOULD NEVER BE COMMITED AND THE `.env` FILE HAS ALREADY BEEN ADDED TO THE [`.gitignore`](./.gitignore).** 🛑 -### Populating The Database +### Populating The Example Database If you choose to populate your database with some initial data you can do so using seed data. We have provided an example of seed data in the [`data.example/`](./server/data.example) folder in a file called [`profiles.mongodb`](server/data.example/profiles.mongodb). @@ -102,3 +108,7 @@ If all's well with the above steps, you should see a list of familiar names. If ## What's Next?! Now it's time to start building your project. + +1. Choose a new database name and update the `MONGO_DB_NAME` value in your `.env` file +2. Create a new `.mongodb` file to populate the database with your data and be sure to update the `use("")` statement with the name you chose above. +3. Define your new API routes and add to server/index.js \ No newline at end of file diff --git a/client/src/services/profileService.js b/client/src/services/profileService.js index 4ceff14..812fbe9 100644 --- a/client/src/services/profileService.js +++ b/client/src/services/profileService.js @@ -3,7 +3,7 @@ import axios from "axios"; const getAllProfiles = async () => { - const response = await axios.get(`/api/profile`); + const response = await axios.get(`/api/profiles`); return response.data || []; }; diff --git a/package.json b/package.json index fdd78e2..55d5854 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,10 @@ "license": "ISC", "dependencies": { "body-parser": "^1.19.0", + "cors": "^2.8.5", "dotenv": "^16.0.3", "express": "^4.17.1", - "mongoose": "^6.9.2" + "mongodb": "^5.1.0" }, "devDependencies": { "concurrently": "^7.0.0", diff --git a/server/index.js b/server/index.js index 5f02dbd..548ecf2 100644 --- a/server/index.js +++ b/server/index.js @@ -1,29 +1,29 @@ require("dotenv").config(); const express = require("express"); -const mongoose = require("mongoose"); +const MongoClient = require("mongodb").MongoClient; const bodyParser = require("body-parser"); +const cors = require("cors"); -// IMPORT YOUR SCHEMAS HERE -require("./models/Profiles"); //This is just an example. Don't forget to delete this - +const PORT = process.env.PORT; const app = express(); -// This is where your API is making its initial connection to the database -mongoose.Promise = global.Promise; -mongoose.set("strictQuery", false); -mongoose.connect(process.env.DATABASE_CONNECTION_STRING, { - useNewUrlParser: true, -}); - app.use(bodyParser.json()); +app.use(cors()); -// IMPORT YOUR API ROUTES HERE -// Below is just an example. Don't forget to delete it. -// It's importing and using everything from the profilesRoutes.js file and also passing app as a parameter for profileRoutes to use -require("./routes/profilesRoutes")(app); +// Connect to the database +MongoClient.connect(process.env.DATABASE_CONNECTION_STRING) + .then((client) => { + const db = client.db(process.env.MONGO_DB_NAME); + // IMPORT YOUR API ROUTES HERE + // Below is just an example. Don't forget to delete it. + // It's importing and using everything from the profilesRoutes.js file and also passing app as a parameter for profileRoutes to use + require("./routes/profilesRoutes")(app, db); -const PORT = process.env.PORT; -app.listen(PORT, () => { - console.log(`API running on port ${PORT}`); -}); + app.listen(PORT, () => { + console.log(`API running on port ${PORT}`); + }); + }) + .catch((err) => { + console.error("Error: ", err); + }); \ No newline at end of file diff --git a/server/models/Profiles.js b/server/models/Profiles.js deleted file mode 100644 index a7d4ebe..0000000 --- a/server/models/Profiles.js +++ /dev/null @@ -1,10 +0,0 @@ -const mongoose = require("mongoose"); -const { Schema } = mongoose; - -const profileSchema = new Schema({ - first_name: String, - last_name: String, - location: String, -}); - -mongoose.model("profiles", profileSchema); diff --git a/server/routes/profilesRoutes.js b/server/routes/profilesRoutes.js index c328181..b60ed8c 100644 --- a/server/routes/profilesRoutes.js +++ b/server/routes/profilesRoutes.js @@ -1,43 +1,91 @@ -const mongoose = require("mongoose"); -const Profile = mongoose.model("profiles"); +const { ObjectId } = require("mongodb"); -const profileRoutes = (app) => { - app.get(`/api/profile`, async (req, res) => { - const profiles = await Profile.find(); +/** + * @param {import('express').Express} app - The Express instance + * @param {import('mongodb').Db} db - The Db instance. + */ +const profilesRoutes = (app, db) => { + /** + * Retrieves the profiles collection from Mongo db + * @returns Collection + */ + const profilesCollection = () => db.collection("profiles"); - return res.status(200).send(profiles); + /** + * Middleware handler for GET requests to /api/profiles path + */ + app.get(`/api/profiles`, async (req, res) => { + try { + // Waits for asynchronous `find()` operation to complete and converts results to array + const profiles = await profilesCollection().find({}).toArray(); + + return res.status(200).send(profiles); + } catch (e) { + return res + .status(500) + .send(`Error occurred while retrieving profiles: ${e}`); + } }); - app.post(`/api/profile`, async (req, res) => { - const profile = await Profile.create(req.body); + /** + * Middleware handler for POST requests to /api/profiles path + */ + app.post(`/api/profiles`, async (req, res) => { + try { + const profile = await profilesCollection().insertOne(req.body); - return res.status(201).send({ - error: false, - profile, - }); + return res.status(201).send({ + error: false, + profile, + }); + } catch (e) { + return res + .status(500) + .send(`Error occurred while creating profile: ${e}`); + } }); - app.put(`/api/profile/:id`, async (req, res) => { - const { id } = req.params; - - const profile = await Profile.findByIdAndUpdate(id, req.body); + /** + * Middleware handler for PUT requests to /api/profiles/:id path + */ + app.put(`/api/profiles/:id`, async (req, res) => { + try { + // Captures target id from URL + const { id } = req.params; + // Builds query matching `_id` field value matching captured id. `ObjectId()` is needed to convert string value to correct type + const query = { _id: new ObjectId(id) }; + const profile = await profilesCollection().replaceOne(query, req.body); - return res.status(202).send({ - error: false, - profile, - }); + return res.status(202).send({ + error: false, + profile, + }); + } catch (e) { + return res + .status(500) + .send(`Error occurred while updating profilee: ${e}`); + } }); - app.delete(`/api/profile/:id`, async (req, res) => { - const { id } = req.params; - - const profile = await Profile.findByIdAndDelete(id); + /** + * Middleware handler for DELETE requests to /api/profiles/:id path + */ + app.delete(`/api/profiles/:id`, async (req, res) => { + try { + const { id } = req.params; + const query = { _id: new ObjectId(id) }; + const profile = await profilesCollection().deleteOne(query); - return res.status(202).send({ - error: false, - profile, - }); + return res.status(202).send({ + error: false, + profile, + }); + } catch (e) { + return res + .status(500) + .send(`Error occurred while deleting profiles: ${e}`); + } }); }; -module.exports = profileRoutes; +module.exports = profilesRoutes;