Skip to content

Step 10: Project 4 MEAN stack implementation

monotiller edited this page Jun 9, 2022 · 2 revisions

MEAN stack deployment to Ubuntu in AWS

Link to discussion

Step 1: Installing NodeJS

First I ran the package manager updater to make sure I had the latest versions of all the installed package. I am running Ubuntu 20.04 so there was a little bit to upgrade:

sudo apt update && sudo apt upgrade -y

Then I added the certificates that would let me install NodeJS and then installed NodeJS itself

sudo apt -y install curl dirmngr apt-transport-https lsb-release ca-certificates
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt install -y nodejs

Step 2: Install MongoDB

Similarly I added the keys for MongoDB and installed the program:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list
sudo apt install -y mongodb

Then I started the server

sudo service mongodb start

Next I installed npm and the node package body-parser:

sudo apt install -y npm && sudo npm install body-parser

A directory named books was created, npm was initialised inside the folder (although all parameters were left at defualt)

{
  "name": "books",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

and a file called server.js was created with the following content:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json());
require('./apps/routes')(app);
app.set('port', 3300);
app.listen(app.get('port'), function() {
    console.log('Server up: http://localhost:' + app.get('port'));
});

Install Express and set up routes to the server

Step 3: Install Express and set up routes to the server

Express is a NodeJS framework that makes it easy to develop apps for both web and mobile and mongoose helps to create schemas for databases. These were both installed with NPM

sudo npm install express mongoose

Next a directory called apps was created inside the books folder, and in there a file called routes.js was created with the following content:

var Book = require('./models/book');
module.exports = function(app) {
  app.get('/book', function(req, res) {
    Book.find({}, function(err, result) {
      if ( err ) throw err;
      res.json(result);
    });
  }); 
  app.post('/book', function(req, res) {
    var book = new Book( {
      name:req.body.name,
      isbn:req.body.isbn,
      author:req.body.author,
      pages:req.body.pages
    });
    book.save(function(err, result) {
      if ( err ) throw err;
      res.json( {
        message:"Successfully added book",
        book:result
      });
    });
  });
  app.delete("/book/:isbn", function(req, res) {
    Book.findOneAndRemove(req.query, function(err, result) {
      if ( err ) throw err;
      res.json( {
        message: "Successfully deleted the book",
        book: result
      });
    });
  });
  var path = require('path');
  app.get('*', function(req, res) {
    res.sendfile(path.join(__dirname + '/public', 'index.html'));
  });
};

Then a directory called models was created with a file inside called book.js

var mongoose = require('mongoose');
var dbHost = 'mongodb://localhost:27017/test';
mongoose.connect(dbHost);
mongoose.connection;
mongoose.set('debug', true);
var bookSchema = mongoose.Schema( {
  name: String,
  isbn: {type: String, index: true},
  author: String,
  pages: Number
});
var Book = mongoose.model('Book', bookSchema);
module.exports = mongoose.model('Book', bookSchema);

Step 4 – Access the routes with AngularJS

In the Books directory a public directory was created with a file inside called script.js:

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
  $http( {
    method: 'GET',
    url: '/book'
  }).then(function successCallback(response) {
    $scope.books = response.data;
  }, function errorCallback(response) {
    console.log('Error: ' + response);
  });
  $scope.del_book = function(book) {
    $http( {
      method: 'DELETE',
      url: '/book/:isbn',
      params: {'isbn': book.isbn}
    }).then(function successCallback(response) {
      console.log(response);
    }, function errorCallback(response) {
      console.log('Error: ' + response);
    });
  };
  $scope.add_book = function() {
    var body = '{ "name": "' + $scope.Name + 
    '", "isbn": "' + $scope.Isbn +
    '", "author": "' + $scope.Author + 
    '", "pages": "' + $scope.Pages + '" }';
    $http({
      method: 'POST',
      url: '/book',
      data: body
    }).then(function successCallback(response) {
      console.log(response);
    }, function errorCallback(response) {
      console.log('Error: ' + response);
    });
  };
});

and a corresponding html document index.html

<!doctype html>
<html ng-app="myApp" ng-controller="myCtrl">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div>
      <table>
        <tr>
          <td>Name:</td>
          <td><input type="text" ng-model="Name"></td>
        </tr>
        <tr>
          <td>Isbn:</td>
          <td><input type="text" ng-model="Isbn"></td>
        </tr>
        <tr>
          <td>Author:</td>
          <td><input type="text" ng-model="Author"></td>
        </tr>
        <tr>
          <td>Pages:</td>
          <td><input type="number" ng-model="Pages"></td>
        </tr>
      </table>
      <button ng-click="add_book()">Add</button>
    </div>
    <hr>
    <div>
      <table>
        <tr>
          <th>Name</th>
          <th>Isbn</th>
          <th>Author</th>
          <th>Pages</th>

        </tr>
        <tr ng-repeat="book in books">
          <td>{{book.name}}</td>
          <td>{{book.isbn}}</td>
          <td>{{book.author}}</td>
          <td>{{book.pages}}</td>

          <td><input type="button" value="Delete" data-ng-click="del_book(book)"></td>
        </tr>
      </table>
    </div>
  </body>
</html>

In the Books directory I started the server with the command

node server.js

However, an error occured:

Apparrently this seems to be a common issue so I found this solution on Stack Overflow which was to simply add the line:

const { TextEncoder, TextDecoder } = require("util");

To the top of the encoding.js file inside ~/Books/node_modules/whatwg-url/lib/. Running the server did give an error:

Although the website did appear when navigated to, entering in a value crashed the server

Then I remembered from project 3 that upgrading the version of NodeJS fixed the issue then so I once again downloaded and installed n which is an version manager and updated to the latest stable version of NodeJS

sudo npm cache clean -f
sudo npm install -g n
sudo n stable

And upon running node server.js again, the server was up and running:

Entering some book information:

Refreshing the page makes the book appear in the list

Clicking delete also removes the book from the list: