Link Search Menu Expand Document

Project C


Released
28 October 2021
Submission
Deadline
12 November 2021 (for Feedback; provided on best-effort basis)
25 November 2021 @ 5 PM EDT
Where Web Submit
Name C
Files
index.js
dao.js
Version
1.0 28 October 2021 Initial Release

Table of contents
  1. Executive Summary
  2. The Environment
    1. Setting up your Environment for Node JS
  3. The Services
    1. GeoNode
    2. Catalog
    3. Trip
  4. Service Implementation
  5. Testing & Deployment
  6. Clean-Up
  7. Submitting Your Work

Executive Summary

This project is similar to Project B (in that you will build a number of web services) except you will use Node JS instead of Tomcat. This allows us to augment our TCP (Project A) and Java (Project B) backend with JavaScript services. You will use all these services in the next two projects to build a shopping-cart web application.


The Environment

It is highly recommended that you use your red account or RemoteLab for this project rather than your own computer. Since we will be using CLI (the command-line interface) for this project, it is very easy to work remotely by ssh’ing to your account. To that end, use your favorite non-GUI editor (such as nano, vim, or emacs) or GUI text editor (VS Code, Atom, or Gedit) to edit your source files.

Setting up your Environment for Node JS

To setup Node JS in your home directory, run these command:

$ eval `4413Load`
$ 4413Load -rc >> ~/.cshrc      # or >> ~/.bashrc
$ 4413Go2

This adds the node_modules directory to your home directory as a symbolic link to a shared copy of the libraries and dependencies your Node JS project might require, and adds the path of the Node JS installation and related files to your PATH environment variable and startup script.

To create a Node JS project named projC in your home directory and create your main (index) script, issue these commands:

$ nodeGo ~/projC
$ cd ~/projC
$ touch index.js

You will be prompted to confirm several options. Accept all their defaults by pressing ENTER and then typing yes at the end of the prompts. This will create a directory named projC directly under your home directory and set it up. Your “servlet” file should be created in it under the name index.js. Once created, you run it using command:

$ node index.js

Since index.js is intended to instantiate a service, the above command will block until you press ^C (Ctrl+C). Any logging on standard output (done in JavaScript via the console.log function) will appear under the above command along with any exceptions thrown.


The Services

This Project asks that you develop and test three microservices with the following functional specifications:

GeoNode

This service is the Node counterpart of the Java GeoWeb service of Project B and the Geo2 service of Project A. It receives two URL-encoded parameters lat and lng containing the GPS coordinates of a place on Earth. If this is the first time this client has made such a request then the return would be the text/plain payload “RECEIVED”. If not, then the return would be the text/plain payload

The distance from (lat1, lng1) to (lat2, lng2) is: XXX km

where XXX is the geodesic distance between the previous place (lat1 and lng1, sent in the last request) and the current one (lat2 and lng2, sent in this request). This can continue (to a 3rd, 4th, … places) as long as the requests are made in the same session. All computations must be made by delegating to the Geo service of Project A, not Geo2 of Project A nor GeoWeb of Project B; i.e. this web service does not do any math.

Making TCP connections from Node JS

To make an TCP connection, use the net modules.

const client = net.createConnection(port, host);

client.on('error', (err) => { /* handle error */ });
client.on('connect', () => {
  client.write('...'); // Send a request
  client.on('data', (data) => { /* use data */ });
  client.end(); // close the socket
});

For the full Node JS documentation and API reference, refer to here.

Catalog

This service receives one URL parameter id containing an integer and returns the id and name of the row corresponding to that id in the Category table of the Models_R_US.db database (which resides in ~/4413/pkg/sqlite). The response should be mimetyped as application/json in the response’s content type. If the id parameter is missing then the response should be an array of json objects for all rows in the table. Here is an example of the response when the request parameter id is 2:

[{"id":2,"name":"Classic Cars"}]

Trip

This service receives two URL parameters from and to containing the start and end addresses of a trip. It returns the optimal distance (in km) and time (in minutes) between them given the current traffic conditions. To get this information, send a request to the MapQuest Directions API (http://www.mapquestapi.com/directions/v2/route?) and supply the following parameters:

Parameter Description
key Your API key, which is needed to make requests to MapQuest services.
from The starting location of a Route Request.
to The ending location of a Route Request.
unit Specifies the type of units to use when calculating distance. Give k for kilometres.
timeType Specifies the time type to use. Give 1 to use the current date/time when generating a route.
useTraffic Set this to true to use historical and realtime traffic speeds to influence the route.

For example, the given request:

GET /Trip?from=4700+Keele+Street%2C+Toronto&to=Canada%27s+Wonderland%2C+Vaughan%2C+Ontario

Your service should response with something like this:

{ "distance": 9.2344, "time": 12.3 }

If no route can be computed, i.e. the response’s info.statuscode attribute is non-zero and the info.messages array attribute contains “Unable to calculate route.”, your service should respond with:

{ "distance": 0, "time": 0 }

Getting a MapQuest API Key

You will need a MapQuest Developer account. To create a new account, register to here. Once you have completed the form and click Sign Me Up, you will be taken to your Profile.

Click Manage Keys on the left navigation to go to your API keys. MapQuest automatically creates you an API key when you first create your account. You can find it by expanding My Application where you will find your Consumer Key. This is your API key, you will use in your GET request.

Making HTTP GET requests from Node JS

To make an HTTP GET request, use the get functions in the http or https modules. For the full Node JS documentation and API reference, refer to here.

Whitespaces in the Location Query

Your from and to query parameters should permit whitespaces to be contained within it. However, URLs cannot contain whitespaces. To get around this, we encode our URLs. See here and here. You can use the built-in global JavaScript function encodeURIComponent or the stringify function in the querystring module.

Testing Tip

You can use an API explorer tool like hoppscotch.io to explore the MapQuest API. For security reasons, by default, Hoppscotch only works with HTTPS requests. To make HTTP requests, you will need to install the Hoppscotch Firefox plugin. Once installed, you should be able to test the MapQuest API and your own web services.


Service Implementation

Use the design patterns, methodologies, and hints demonstrated in lecture in order to speed up development and learn best-practice approaches.

Develop all 3 services in one project, but each in its own middleware (i.e. app.get) function. The route (URL mapping) should be the same as the service name. Use the following fragment as a template for your index.js:

const express = require('express');
const session = require('express-session');
const dao     = require('./dao.js');

const app  = express();
const port = process.argv[2] || 3000;

app.enable('trust proxy');
app.use(session({
  secret: 'secret',
  resave: true,
  saveUninitialized: true,
  proxy: true
}));

app.get('/GeoNode', function (req, res) { /* ... */ });
app.get('/Catalog', function (req, res) { /* ... */ });
app.get('/Trip',    function (req, res) { /* ... */ });

const server = app.listen(port, function () {
  const host = server.address().address;
  const port = server.address().port;
  console.log(`server listening to ${host}:${port}`);
});

And in your dao.js:

const os      = require('os');
const path    = require('path');
const sqlite3 = require('sqlite3');

const dbfile  = '4413/pkg/sqlite/Models_R_US.db';
const dbpath  = path.join(os.homedir(), ...dbfile.split('/'));
const db      = new (sqlite3.verbose()).Database(dbpath);

module.exports = {
  getCatalog(id) {
    /* ... */
  }
};

Testing & Deployment

Test your services through a browser using http://host:port?qs, where qs is the query string. Use localhost with port 3000 (or a port specified via the command-line arguments) when testing on a workstation.

Once everything is working, start the the service on a workstation, copy down the hostname (e.g.: ea75) and port number, log into red (rather than a workstation) by simply ssh‘ing to it, run firefox (you will need to close any opened Firefox instances on your workstation) and then connect to the running web service on the workstation from red (e.g.: make requests to the services at http://ea75.eecs.yorku.ca:3000/). Please DO NOT run your service directly on red as the non-standard ports are blocked and red is a shared environment.


Clean-Up

Do not leave services running unnecessarily in the background on time-shared servers — they will consume system resources. Once you are done with a service, terminate it. Use the fg/bg commands or ps -u and kill to list and terminate all you services on red, red1, and red2.


Submitting Your Work

Simply upload your index.js and dao.js to the course cloud so you can use it during tests. (You can also upload it to your Github, Google Drive, DropBox, S3, or some other cloud service).

$ submit 4413 C index.js dao.js

Back to top

Copyright © 2021 Vincent Chu. Course materials based on and used with permission from Professor Hamzeh Roumani.
Last updated: 05 January 2022 at 06:16 PM EST