/* s41 - Express.js - Data Persistence via Mongoose ODM */ const express = require('express'); const mongoose = require('mongoose'); const app = express(); const port = 3001; // [Section] MongoDB Connection /* Syntax: mongoose.connect("", { useNewUrlParser: true, useUnifiedTopology: true }); */ // Connecting to MongoDB Atlas mongoose.connect("mongodb+srv://jerrycabuntucan:EvDaqSDV8DIXZTQr@b320-cluster.ke6t1wi.mongodb.net/b320-todo?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true }); // Set Notifications for connection success or failure let db = mongoose.connection; // If a connection error occurred, output in the console // console.error.bind(console) allows us to print error in the browser console and in the terminal db.on("error", console.error.bind(console, "connection error")); // If the connection is successful, output in the console db.once("open", () => console.log("We're connected to the cloud database!")); // [Section] Mongoose Schema /* - Schemas determine the structure of the documents to be written in the database - It will act as a blueprint to our data(documents) */ // The "new" keyword creates a new Schema const taskSchema = new mongoose.Schema({ // Define the fields with the corresponding data type // The field called "name" and its data type is "String" name: String, // This is the "status" field that is a "String" and the default value is "pending" status: { type: String, default: "pending" } }); //User Schema const userSchema = new mongoose.Schema({ username: String, password: String }); // [Section] Models /* - It uses schemas and are used to create/instantiate objects that correspond to the schema - Models use Schemas and they act as a middleman between the server(JS code) to our database(MongoDB) - Server > Schema (blueprint) > Database > Collection */ const Task = mongoose.model("Task", taskSchema); //User Model const User = mongoose.model("User", userSchema); // Middlewares app.use(express.json()); app.use(express.urlencoded({extended: true})); // [Section] Routes // Creating a new task /* Business Logic: 1. Add a functionality to check if there are duplicated tasks - If the task already exists in the DB, we return an error - If the task doesn't exist in the DB, we add it in the DB 2. The task data will be coming from the request's body 3. Create a new Task object with a "name" field/property 4. The "status" property does not need to be provided because our schema defaults it to "pending" upon creation of an object */ app.post("/tasks", (req, res) => { // It will search the req.body.name in the db to check if it exist already in the db Task.findOne({name: req.body.name}).then((result, err) => { // If a docuent was found and the document's name matches the information sent via the client/postman if(result != null && result.name == req.body.name){ // Return a message to the client/Postman return res.send("Duplicate task found"); // If no document as found } else { // Create a new task and save it to the database let newTask = new Task({ name: req.body.name }); // The .save method is used to save the new object to the database newTask.save().then((savedTask, saveErr) => { // If there are errors in save, console.error the error if(saveErr){ return console.error(saveErr); // No error found while creating the document, return a response } else { // Return a status code of 201, which means created successfully // Sends a message "New task created" on successfull creation return res.status(201).send("New task created"); } }); } }) }); // Getting all the tasks /* Business Logic: 1. Retrieve all the documents. 2. if an error is encountered, print the error. 3. If no errors are found, send a success status back to the client/Postman and return an array of documents. */ app.get("/tasks", (req, res) => { // "find" is a Mongoose method used to retrieve documents in the database, and with {}, we are going to retrieve all the documents Task.find({}).then((result, err) => { // If an error occurred if(err){ // Will print any errors found in the console return console.error(err); // If no errors are found } else { // The returned response is added in an object with the "data" property. // status "200" means that everything is "OK" // The "json" method allows us to send a JSON format for the response return res.status(200).json({ data: result }); } }); }); app.post("/signup", (req, res) => { console.log(req.body); User.findOne({username: req.body.username}).then((result,err) => { if(result != null && result.username == req.body.username){ return res.send("Duplicate username found"); } else { if(req.body.username !== "" && req.body.password !== ""){ let newUser = new User({ username: req.body.username, password: req.body.password }); newUser.save().then((savedUser, savedErr) => { if(savedErr){ return console.error(savedErr); } else{ return res.status(201).send("New User Registered"); } }) } else { return res.send("BOTH username and password must be provided"); } } }) }); if(require.main === module){ app.listen(port, () => console.log(`Server running at port ${port}`)); } module.exports = app;