Angular, MongoDB (mongoose), Express Summary

  1. Work with Postman.
    1. Create Collection Mission5 .
    2. Create Get request
      localhost:5000/api/items
    3. Create Post request
      localhost:5000/api/items
      • Select POST request
      • Body Type: raw
      • Select JSON
      • Body Content:
          {
            "name": "test",
            "status": true
          }
                      

  2. Open VC Code for this project only.
  3. Create project mission5 in VS Code.
  4. Put .gitignore file into this folder.
  5. Create myNotes.txt file in this folder.

  6. Angular
    1. Install Angular
        cd mission5
        ng new client
      
    2. Clean files.

    3. Change routing file location
      1. Create folder
          src\app\app-routing
        
      2. Move there
          app-routing.module.ts file
        
    4. Install Bootstrap
          cd client
          npm i bootstrap
        
    5. Add to the project
      • Way 1

        In style.css write

        @import "bootstrap/dist/css/bootstrap.min.css";
                      

      • Way 2

        Update angular.json file.

                    
            "styles": [
              "src/styles.css",
              "./node_modules/bootstrap/dist/css/bootstrap.min.css"
            ],                     
          
    6. Models: src\models\Response.ts
                  export interface Response {
                    success: boolean;
                    data?: any
                  }            
                
    7. Services

      1. Create a service ng g s services/tasks --skipTests=true

      2. In app.module
          import { HttpClientModule } from '@angular/common/http';  
          import { UsersService } from './services/users.service';
          ...
          imports: [
            ...
            HttpClientModule
          ],  
          ...
          providers: [UsersService],
        
      3. services/tasks.service.ts
          import { Injectable } from '@angular/core';
          import { HttpClient, HttpHeaders } from '@angular/common/http';
          import { Observable } from 'rxjs';
          import { Response } from '../models/Response';
          import { Task } from '../models/Task';
        
          const httpOptions = {
            headers: new HttpHeaders({
              'Content-Type': 'application/json'
            })
          }
        
          @Injectable({
            providedIn: 'root'
          })
          export class TasksService {
            rootUrl: string = 'http://localhost:5000/tasks';
        
            constructor(private http:HttpClient) { }
            
            // GET
            getTasks():Observable<Response> {
              const url = `${this.rootUrl}`;
        
              return this.http.get<Response>(this.rootUrl);
            }
        
            // POST
            addTask(task: Task):Observable {
              return this.http.post(this.rootUrl, task, httpOptions);
            }
        
            // PUT
            updateComment(comment: Comment): Observable<Response> {
              const currUrl: string = `${this.urootUrlrl}/${comment._id}`;
          
              return this.http.put<Response>(currUrl, comment, httpOptions);
            }
        
            // DELETE
            deleteTask(_id: string):Observable<Response> {
              const url = `${this.rootUrl}/${_id}`;
        
              return this.http.delete<Response>(url);
            }
          }
        
    8. Routing
      1. app-routing\app-routing.module.ts
          import { NgModule } from '@angular/core';
          import { Routes, RouterModule } from '@angular/router';
        
          const routes: Routes = [
            {path: '', component: HomeComponent},
            {path: 'comment/:id', component: CommentDetailsComponent},
            {path: '**', component: NotFoundComponent}
          ];
        
          @NgModule({
            imports: [RouterModule.forRoot(routes)],
            exports: [RouterModule]
          })
          export class AppRoutingModule { }
        

      2. scr\app\app.component.html
          <div class="container mt-4">
            <router-outlet></router-outlet>
          </div>  
        

  7. Install Server Side packages
    Create server.js file.
    npm init -y
    npm i express mongoose cors dotenv

    Update package.json file

            "scripts": {
              "start": "node server.js",
              "server": "nodemon server.js --ignore ./client",
              "client": "npm start --prefix client"
            },
          

  8. Work with MongoDB

    1. Create mission5 collection using MongoDB site.
    2. Open Compass and connect to the collection URI

  9. Server Side

    1. .env file
                  MONGODB_URI=<mongo uri>
                

    2. db\db.js file
                  const mongoose = require('mongoose');
      
                  const db = process.env.MONGODB_URI;
                  
                  const connectDB = async () => {
                    const options = {
                      useNewUrlParser: true, 
                      useUnifiedTopology: true
                    };
                  
                    try {
                      await mongoose.connect(db, options);
                      console.log('MongoDB connected...');
                    } catch(err) {
                      console.log('MongoDB was not connected...'); 
                      process.exit(1);
                    }
                  }
                  
                  module.exports = connectDB;
                  
                  
                

    3. models\task.js
              const mongoose = require('mongoose');
      
              const TaskSchema = new mongoose.Schema({
                  taskName: {
                    type: String, 
                    required: true
                  },
                  owner: {
                    type: mongoose.Schema.Types.ObjectId,      
                    ref: 'Owner' // reference to the collection in database
                  },
                  createdAt: {
                    type: Date, 
                    default: Date.now
                  },
                }
              );
      
              const Task = mongoose.model('Task', TaskSchema);
      
              /*                           <----------------   Run Once
              Owner.insertMany([
                {firstName: "Isak", lastName: "Levinson"}, 
                {firstName: "Raya", lastName: "Levinson"}, 
                {firstName: "Meshi", lastName: "Levinson"}
              ]);
              */
      
              module.exports = Task;
      

    4. server.js file
                  require('dotenv').config();
                  const express = require('express');
                  const cors = require('cors');
                  const connectDB = require('./db/db');
                  
                  const app = express();
                  
                  // Connect database
                  connectDB();
                  
                  // Body Parser Middleware 
                  app.use(express.json());
                  
                  app.use(cors({
                    origin: "http://localhost:4200",
                    credentials: true                     <--------------- optional
                  }));
                  
                  ///////////////////
                  // GET
                  app.get('/api/items', (req, res) => {            
                    res.status(200).json({});
                  });
      
                  // POST
                  app.post('/api/items', (req, res) => {
                    res.status(200).json({});
                  });
      
                  ///////////////////
      
                  // Middleware that catches errors - should be at the end
                  app.use((err, req, res, next) => {
                    if (err) {
                      console.log(err);
                      res.status(500).json({ success: false });
                      return; // important
                    }
                    next();
                  });
      
                  const PORT = process.env.PORT || 5000;
                  app.listen(PORT, () => {
                    console.log(`Server Started on Port ${PORT}`);
                  });
                

    5. GET
                  // GET
                  
                    app.get('/members', async (req, res, next) => {
                      try {
                        const data = await Member.find();
                        return res.status(200).json({ success: true, data });
                      } catch (err) {
                        return next(new Error(err));
                      }
                    });
                  

    6. GET and POST
                  // GET and POST
                  
                  app.route('/tasks')
                  .get (async (req, res, next) => {
                    try {
                      const data = await Task.find().populate('owner');
                
                      return res.status(200).json({ success: true, data });
                    } catch (err) {
                      return next(new Error(err));
                    }
                  })
                  .post (async (req, res, next) => {
                    const { taskName, owner } = req.body;
                
                    const newTask = { taskName, owner };
                
                    if (await isTaskValid(newTask)) {
                      try {
                        const data = await Task.create(newTask);
                  
                        return res.status(200).json({ success: true, data });
                      } catch (err) {
                        return next(new Error(err));
                      }
                    } else {
                      return res.status(400).json({ success: false });
                    }
                  });           
                

    7. PUT
                  // PUT
                 
                  app.route('/comments/:id')  
                  .put (async (req, res, next) => {
                    if (isCommentValid(req.body)) {
                      const _id = req.params.id;
                      const { title, content, likes } = req.body;
                  
                      let commentFields = {}
                      if (title) commentFields.title = title;
                      if (content) commentFields.content = content;
                      if (likes) commentFields.likes = likes;
                      
                      try { 
                        const comment = await Comment.findByIdAndUpdate(_id, 
                            { $set: commentFields },
                            { new: true });
                        if (comment) {
                          return res.status(OK).json({ success: true, comment });
                        } else {
                            return res.status(BAD_REQUEST).json({ success: false });
                        }    
                      } catch (err) {
                        return next(new Error(err));
                      }
                    } else {
                      return res.status(BAD_REQUEST).json({ success: false });
                    }  
                  }
                

    8. DELETE
                  //DELETE
      
                  app.route('/tasks/:id')  
                  .delete (async (req, res, next) => {
                    const _id = req.params.id;
                
                    try {
                      const result = await Task.deleteOne({ _id });
                
                      if (result.deletedCount > 0) {
                        return res.status(200).json({ success: true });
                      } else {
                          return res.status(400).json({ success: false });
                      }
                    } catch (err) {
                      return next(new Error(err));
                    }
                  });                        
                

  10. How to create Proxy in Angular
    1. Create proxy.conf.json file under client folder with:
      {
      "/api/*": {
        "target": "http://localhost:5000",
        "secure": false
      }
      }
      
    2. Update angular.json file.
      ...
      "serve": {
      "builder": "@angular-devkit/build-angular:dev-server",
      "options": {
        "browserTarget": "client:build",
        "proxyConfig": "proxy.conf.json"    <-------- Add this line only!!!
      },
      

  11. Client Side See Angular Summary