Categories
Technically Speaking

ExpressJS and building a solid NodeJS stack

Motivation

We at Orpheus Digital made a decision to try out a NodeJS stack. After much research, we decided to go for the most famous stack – ExpressJS. Currently, PHP over a CodeIgniter framework drives almost all our server-side systems. This stack performs well. However, the decline in popularity of CodeIgniter pressured us to adopt a more modern tech stack.

Despite this, we do not see ourselves deprecating the CodeIgniter stack anytime soon. It is quite fast, reliable and incredibly easy to setup. NodeJS will serve as another choice when developing a server-side application – it will exist beside our tried and tested solution that is CodeIgniter.

Although this is the first in-depth dive into NodeJS, we have several tutorials using NodeJS stacks like using GCE to run a NodeJS app.

Easier ExpressJS development

By default, updating application files will not update the server during ExpressJS development. Therefore, we need to manually start and stop the server. To prevent this, we can use a tool called nodemon. Servers started with nodemon will automatically reload files as they are being saved.

Next, we will look at how we can install nodemon. It is quite easy:

npm install -g nodemon

Adding nodemon is not compulsory. However, it is an incredible time saver!

ExpressJS file structure

ExpressJS does not enforce a strict directory structure. Therefore, we have total freedom over file management. Firstly, we will use the express-generator tool to setup an ExpressJS project.

npx express-generator -h
npx express-generator --view=hbs --git ej-server

This creates a folder called ej-server which has a directory structure similar to the one shown below

Directory structure of a folder created using the ExpressJS generator tool
An example directory structure created using the express-generator tool

Next, we need to download the dependencies (which will create a node_modules folder).

cd ej-server
npm install
nodemon bin/www

The advantage of this method is that it sets up some default behaviour out of the box:

  • Adds support for a public directory where static resources can be stored. The generated boilerplate already has support for serving these static files!
  • Two sample routes (/ route and a /users route) along with route handling
  • Handlebars-based templating system

An advantage of our previous CodeIgniter stack was that API calls and the backend UI could be handled on the same repository. We will add similar functionality for the ExpressJS stack as well.

Now that we have created our stack and files, let’s look at a way to deploy the ExpressJS application.

Deploy ExpressJS app on cPanel

Most cPanel-based shared hosting services also let advanced users serve NodeJS apps. We will look into how this can be done.

If your cPanel account supports this feature, you will see an icon like this:

Click on the “Create Application” button to create a new NodeJS application. You will be greeted with a form similar to the one shown below:

cPanel page to set up a new NodeJS app

This feature does not provide a file uploader. You have to manually upload the NodeJS files using FTP or GIT. This location is the one you have to specify in the ‘Application root’ property.

Running npm install

After getting files, you should run npm install before the application can work. Copy the code to enter the virtual environment that is provided on the Node.js Application page. After pasting the code on an SSH terminal, you should be in the virtual environment of the application. Here you can execute your npm install command.

Serve a public folder

Since this application will also serve HTML pages, the pages need to be able to access static content like CSS and JS. ExpressJS has a built in function to facilitate this:

express.static(path.join(__dirname, 'public'))

Serve as a subfolder

When it comes to serving on a production server, you have to serve as a child URL of the top-level domain. For example, if the domain is example.org, the application will have to be served from example.org/app. This is a production-specific problem. The best way to go about this is to have redesign the routing hierarchy – a parent route will take care of handling requests to the subfolder, i.e. /app. All requests to this subfolder will be routed to child routes of the parent. This method is detailed in this article.

What should be remembered is that if you opt to go with this method, the public folder will also be served as a sub-route of /app. Therefore, to access a CSS in the public folder from an HTML file, you will have to load the resource from /app/stylesheets/style.css instead of stylesheets/style.css

Gotchas

cPanel uses an application called Phusion Passenger to serve NodeJS applications. It uses something called reversed port binding to serve the NodeJS app. An in-depth look at this method and its consequences is available on https://www.phusionpassenger.com/library/indepth/nodejs/reverse_port_binding.html

An implication of this architecture is that the NodeJS application can have only one createServer().listen() otherwise Passenger gets confused. NodeJS applications served this way cannot specify their port. Passenger ignores any specified ports. Instead, it listens on a random Unix domain socket.

Another common mistake is specifying app.js as the application startup file. This property should always mention the script that calls the initial createServer().listen()

Categories
Technically Speaking

UPchieve – Adding Subject Categories

Previously on Technically Speaking, we discussed about setting up the UPchieve platform and making fundamental configurations to both the web frontend and the server. In this article, we discuss about other configuration options

Before we can add categories, we have to remove the existing categories. The system determines categories using the categories the questions are added under.

The easiest way to do is to use the mongo command line.

mongo

use upchieve
db.question.remove({})

Or we can use the Edu Admin dashboard by going to

http://<server>.example.org/edu
UPchieve Edu admin - add a question view
UPchieve Edu admin – add a question view

But make sure you have logged in as an Admin user to the UPchieve web client first.

After we have cleared the question collection, we can add our own questions using the Edu Admin dashboard. However, this procedure on its own will not update all mentions of the categories on the site. Some mentions we do have to update ourselves.

Changes to the web client

Firstly, we need to update the categories that appear in the subject selection area of the student dashboard. We need to update the topics.js file at;

/src/utils/topics.js

When creating the topics and subtopics in topic.js, make sure you make the displayName and the key name the same. (This might be a bug)

Changes to the server-side

We need to manually update the questions model at;

/models/Question.js (line 24 onwards)

The categories and subcategories here are not referring to the category and subcategory on the student dashboard! These subcategories refer to certain areas of the the subject. For example: if there is a a super category on the student dashboard called “IAL”, with a subcategory called “Maths”, the Question.js category should be “science” and subcategory should be, let’s say, “calculus”.

/models/Session.js (line 6)
/controllers/TrainingCtrl.js (line 7 onwards)
/utils/getSupercategory.js

Then we have to modify the certification entries that are stored in the database along side the user names, we have to modify;

/models/User.js (line 236 onwards)

If everything has worked fine, you should be able to see the new categories throughout the server API and web frontend.