Creating RESTful Web Services with MEAN

  1. Overview
    1. Node, Express, MongoDB, and Mongoose are frequently used to create web services or APIs
    2. Express runs on Node to create a web server that responds to API requests
    3. Mongoose is used to interact with the database on MongoDB
    4. Later we will consume the web services with jQuery and/or AngularJS
  2. Creating a web service in WebStorm
    1. Create a new empty project in WebStorm
    2. Creating a web server with Express
      1. Server will use several Node packages
        1. Express and Mongoose
        2. Morgan for logging the HTTP requests
          npm install --save morgan
          
        3. Body-parser for parsing JSON
      2. Create server.js
        var logger = require('morgan');
        var express = require('express');
        var bodyParser = require('body-parser');
        var mongoose = require('mongoose');
        
        var app = express();
        app.use(bodyParser.json());
        
        // Send all HTTP requests with /api/students to the students controller
        app.use('/api/students', require('./controllers/students'));
        
        // Shows HTTP requests in the console
        app.use(logger('dev'));
        
        // Connect to the "test" database
        mongoose.connect('mongodb://localhost/test', function(err, res) {
            if (err) {
                console.log('Error connecting to MongoDB database. ' + err);
            }
            else {
                console.log('Connected to database');
            }
        });
        
        // Route requests to files in the local directory
        app.use(express.static(__dirname + '/'));
        
        // Serve root page
        app.get('/', function(req, res) {
            res.status(200).send('Hello Express!');
        });
        
        app.listen(4000);
        console.log("Server is listening on port 4000");
        
      3. Start server in WebStorm and access root page in browser
        http://localhost:4000/
        
    3. Creating the model
      1. The Mongoose model will be transformed into JSON when transmitted to and from the web service
      2. Create models/student.js
        var mongoose = require('mongoose');
        
        var Student = mongoose.model('Student', {
            name:      String,
            gpa:       { type: Number, min: 0, max: 4 },
            interests: [String],
            enrolled:  Boolean
        });
        
        module.exports = Student;	
        
    4. Creating API controllers
      1. Controllers implement the GET, POST, UPDATE, and DELETE http methods
      2. Uses the Express router which acts as middleware and routes http requests to the controllers
      3. Create controllers/students.js
        var Student = require('../models/student');
        var router = require('express').Router();
        
        // TODO: Handle http requests here...
        
        module.exports = router;
        
      4. GET request (retrieve resources)
        1. Retrieve all students
          // Get all students
          // http://localhost:4000/api/students
          router.get('/', function(req, res, next) {
              console.log('Get all students');
              Student.find(function(err, students) {
                  if (err) return next(err);
                  res.json(students);
              });
          });
          
        2. Returns 200 response with all students
          [
              {
                  "_id": "54bffe89a9c2f8085c695e3a",
                  "name": "Bob Smith",
                  "gpa": 5.3,
                  "__v": 0,
                  "interests": [
                      "hiking"
                  ]
              },
              {
                  "_id": "54bffee6eb4fd9fc5db271ed",
                  "name": "Larry White",
                  "gpa": 4.5,
                  "__v": 0,
                  "interests": [
                      "volleyball",
                      "gaming",
                      "fantasy football"
                  ]
              },
          	etc...
          ]
          
        3. Retrieve students that match a given criteria
          // Get student with given ID
          // http://localhost:4000/api/students/id/54bffee6eb4fd9fc5db271ed
          router.get('/:id', function(req, res, next) {
              console.log('id = ' + req.params.id);
              Student.findById(req.params.id, function(err, stu) {
                  if (err) return next(err);
          
                  res.json(stu);
              });
          });
          
      5. POST request (create new resource)
        1. Create a new student
          // Add new student
          router.post('/', function(req, res, next) {
          
          	// Create a new student from JSON request body
              var student = new Student({
                  name: req.body.name,
                  gpa: req.body.gpa,
                  enrolled: req.body.enrolled,
                  interests: req.body.interests
              });
          
          	// Save student and return it as JSON
              student.save(function(err, stu) {
                  if (err) return next(err);
                  res.json(stu);
              });
          });
          
        2. POST the following JSON to /api/students using HTTP header Content-Type: application/json
          {
          	"name": "Becky Brown",
          	"gpa": 4.0,
          	"enrolled": true,
          	"interests": [
          		"programming",
          		"tennis"
          	]
          }
          
      6. PUT request (update existing resource)
        1. Update an existing student
          // Update existing student
          router.put('/', function(req, res, next) {
          
          	// Make sure the student ID was sent
          	var stuId = req.body._id;
          	if (stuId === undefined) {
                  res.status(400).json({ message: 'Student ID is missing' });
                  return next();
              }
          
          	// Update the student with values from the request
              Student.findByIdAndUpdate(stuId, req.body, function(err, stu) {
                  if (err) return next(err);
                  if (stu === null)
                      res.status(404).json({ message: 'Student not found' });
                  else
                      res.json(stu);
              });
          });
          
        2. PUT to /api/students/ using HTTP header Content-Type: application/json
          {
          	"_id": "54d52686400ee3282c1e2f89",
          	"name": "Becky B. Brown",
          	"gpa": 3.5
          }
          
      7. DELETE request (delete existing resource)
        1. Update an existing student
          // Delete existing student with the given ID in the URL
          router.delete('/:id', function(req, res, next) {
          
          	// Make sure the student ID was sent
          	var stuId = req.params.id;
          	if (stuId === undefined) {
                  res.status(400).json({ message: 'Student ID is missing' });
                  return next();
              }
          
          	// Delete this student
              Student.findByIdAndRemove(stuId, function(err, stu) {
                  if (err) return next(err);
                  if (stu === null)
                      res.status(404).json({ message: 'Student not found' });
                  else
                      res.json({ message: 'Successfully deleted' });
              });
          });
          
        2. DELETE to /api/students/id with ID of student to delete