fake book web application - scs. · pdf file1 fake book web application author: ahmad masoud...
TRANSCRIPT
1
Fake Book Web
Application
Author: Ahmad Masoud
Course: COMP 4905
Supervisor: Dr. Louis D. Nel - (School of Computer Science)
Date: April 10, 2016
2
Abstract
Music students and teachers use fake books, books that contain a collection of musical
lead sheets, as a source of songs. The database course offered at Carleton university provides a
database containing indexing data for fake books, used as a basis for course assignments. Along
with this database, a Java/Swing application was developed to provide a GUI (General User
Interface) that allows users to access the data in the database. Due to student interest in the
Node.js runtime environment and multiple advantages such as ease of configuration, a Node.js-
based web application was to be developed to replace the traditional Java/Swing application.
The following report describes the development of this Node.js-based application, specifying
details of the design and implementation of both the server and client side.
3
Acknowledgements
I would like to thank Dr. Louis D. Nel for providing the database containing the book and song data used in the development of this application.
4
Table of Contents
List of Figures ........................................................................................................................ 5
List of Tables ......................................................................................................................... 6
Introduction .......................................................................................................................... 7
Design ................................................................................................................................... 8 Client-Server Communication Method ............................................................................................8 Server Structure ........................................................................................................................... 12 Client Structure ............................................................................................................................ 13
Implementation .................................................................................................................. 14 Server .......................................................................................................................................... 14 Client ........................................................................................................................................... 21
Results ................................................................................................................................ 27
Conclusion ........................................................................................................................... 29
References .......................................................................................................................... 30
5
List of Figures FIGURE 1: proper use of HTTP methods in a REST-based architecture .......................................... 8
FIGURE 2: using the Express framework’s routing methods to handle HTTP requests ................. 9
FIGURE 3: using jQuery’s ajax function to retrieve all books from the server ............................. 10
FIGURE 4: generic representation of the server structure ........................................................... 12
FIGURE 5: example of using the getBooks function ..................................................................... 17
FIGURE 6: definition of the socket message and event handlers ................................................. 19
FIGURE 7: the user interface of the book table ............................................................................ 27
FIGURE 8: the user interface of the song table ............................................................................ 28
6
List of Tables TABLE 1: result of sending an HTTP request with the given HTTP method to the given URI ......... 9
TABLE 2: result of passing the given query string as an argument to the doSelect function....... 14
TABLE 3: name of each client request function, its purpose, and the name of its corresponding server response handler function ......................................................................................... 23
7
Introduction One source of songs for many music teachers and students is fake books, books that
contain a collection of musical lead sheets for multiple songs. These books help musicians learn
songs quickly by allowing them to analyze the harmony and learn to play the tunes. The
databases course offered at Carleton University currently provides an SQLite database that
stores indexing data for fake books. This database consists of two tables, bookcodes and
songs. The bookcodes table contains book information which consists of a unique book
code, book title, name of the file that contains the book, format of the file, and the page offset
which specifies the page number where the content of the book first appears on (i.e. the first
song). The songs table contains song information which consists of a unique song id, the song
title, the code of the book that the song is in, and the page number that the song appears on.
This fake book indexing database is used as the basis for course assignments, allowing students
to get hands on experience with relational databases and SQL queries. Along with the database,
a Java/Swing application was developed to provide a GUI (Graphical User Interface) to allow
users to access and search the data contained in the database. One downside of using the Java-
based application is configuring the application to run on different operating systems, which
can be a hassle.
The goal of this project was to develop a Node.js-based web application to replace the
traditional Java/Swing application. Node.js has gained very much popularity and is the platform
that many developers are choosing to create server side web applications. It has an excellent
cross-platform support, allowing an application to be easily configured and executed on
different operating systems (i.e. Windows, Linux, OSX). Using a Node.js-based application
allows users to easily set up the application in a short time regardless of the operating system
they are using. Also, having a Node.js/JavaScript application as the basis of course assignments
will allow students to gain more understanding/experience with Node.js which can be of great
help in the future as this technology is growing rapidly. Furthermore, this application will not
only be useful to students who are enrolled in the databases course but also other people such
8
as music students and teachers who make use of fake books. This report provides a detailed
overview of the development of the fake book web application.
Design
One of the first and most important steps taken during the development of the
application was the design. This section describes the different aspects of the application design
which include the communication method between the client and the server, the server
structure, and the client structure.
Client-Server Communication Method
There were two client-server communication methods that were analyzed. The first
method involved the sole use of HTTP (HyperText Transfer Protocol) to exchange data between
the client and the server, while the second method involved the use of WebSockets.
The first method that was examined involved the development of a RESTful API on the
server side. In this design, the server and client communicate using HTTP, exchanging
data/resources in the JSON (JavaScript Object Notation) format. The server would provide
access to the fake book data contained in the database and the client would be able to retrieve,
create, modify, or delete data by sending HTTP requests to the server. HTTP provides multiple
methods that can be performed on a URI (Uniform Resource Identifier) to read, create, modify,
or delete resources. The four main methods that are used in a REST-based architecture are GET,
POST, PUT, and DELETE. Fig. 1 shows the proper use of each method in a REST-based
architecture.
FIGURE 1: proper use of HTTP methods in a
REST-based architecture
9
This approach requires the fake book application server to define the URI’s or paths that expose
its resources (book and song data), hence allowing the client to access these resources by
sending an HTTP request containing the appropriate HTTP method and one of the defined
URI’s. Table 1 shows possible examples of this.
TABLE 1: result of sending an HTTP request with the given HTTP method to the given URI
HTTP Method URI Result
GET /books Retrieve all books
POST /books Create a new book
PUT /books/XXXX Update the book with code XXXX
DELETE /books/XXXX Remove the book with code XXXX
Defining such URI’s or endpoints is made much simpler with the use of Express, a web
application framework for Node.js. Express provides routing methods that correspond to HTTP
methods. These methods can be used to define routes that handle client requests made to
URI’s. A route definition has the form app.METHOD(URI, HANDLER) where app is the
object denoting an instance of the Express application, METHOD is the HTTP method to match,
URI is the endpoint identifying a resource, and HANDLER is the function that is executed if the
route corresponds to the request made by the client. Fig. 2 shows how these routing methods
can be used to handle client requests in the context of the fake book application.
FIGURE 2: using the Express framework’s routing methods to
handle HTTP requests
10
Once all the routes are defined on the server side, the next thing that was considered in this
approach was the way the client will make the HTTP requests to the server and AJAX
(Asynchronous JavaScript and XML) was the first thing that came to mind. AJAX is a technique
that allows for the creation of dynamic, fast, and interactive web pages. With AJAX, clients can
make asynchronous HTTP requests to exchange data with the server while dynamically
updating the web page. This implies that a client is not required to reload a page to obtain new
or updated data from the server. Using AJAX on the client side is made simple with the use of
the jQuery JavaScript library. The jQuery library provides a method called ajax that is used to
send an HTTP (AJAX) request. This method takes a settings object as an argument, containing
multiple properties such as the HTTP method to use and the url the request is made to. Among
the properties that can also be included in the settings object are a success function and an
error function. The success function is called if the request was successful while the error
function is called if the request fails. Fig. 3 shows how the ajax method can be used to
retrieve all books from the server.
The main advantage of having a RESTful API on the server side and using HTTP to exchange data
between the server and client is statelessness. This implies that each request made by the
client can be treated independently by the server. This also implies that a client’s state or
previous interactions are never stored on the server, thus simplifying the server design.
However, in the context of the fake book application, this can have some limitations. The fake
book application should be designed to support multiple clients simultaneously accessing book
FIGURE 3: using jQuery’s ajax function to retrieve all books from the server
11
and song data. Relying solely on HTTP requests for exchanging data with the server implies that
if the database was updated by one client, other connected clients would not be able to see the
updates made until they send a new request to the server to obtain that data. More
importantly, due to the stateless nature of the server, there is no way for the other clients to
know if the database was updated to allow them to quickly send that request to the server. This
can have many negative effects on the fake book application including the possibility of a client
updating outdated book or song data or attempting to remove a book or song that no longer
exists because it was removed by another client. A possible solution to this problem is for all
clients to send frequent requests, possibly every few seconds, to obtain the latest data in the
database. However, this solution can be inefficient and can overload the server with many
unnecessary requests.
The second method of communication between the client and server that was analyzed
was the use of WebSockets. In this design, the client and server would communicate via
WebSockets through an interactive and persistent communication session. This communication
session is first established when the client attempts to connect to the server by sending an
HTTP request which includes an “upgrade” header that indicates a request to establish a
WebSocket connection. The server would agree to this request by sending the “upgrade”
header in the HTTP response. This process is known as the handshake. Once the
handshake is successfully completed, communication between the client and server is done
through a TCP/IP connection. The main advantage of using WebSockets to exchange data
between the server and client is the low latency and persistent connection which reduces
overhead. This connection allows both the server and client to push messages/data to each
other, thus removing the need for the client to poll the server for updates. In the context of the
fake book application, this implies that if one client updates book or song data, the server
would be able to notify all other connected clients about this update, thus allowing all clients to
have access to the latest data contained in the database at any point in time.
12
After analyzing both of these client-server communication methods, the method that
was considered to be more advantageous with respect to the fake book application was
WebSockets. Implementation of WebSocket communication between the client and the server
would be done using the Socket.IO JavaScript library which provides both a server API and a
client API to simplify this process.
Server Structure
With respect to the structure of the server, the modules contained in a directory called
lib would handle all database queries. In order to accomplish this while providing a higher
level of abstraction, development of two modules was required. One module, called
database.js would handle direct communication with the database, while another module
called query.js would use the database.js module to handle requested queries. Both of
these modules will be designed to follow the Node.js callback concept. This implies that all
exported functions in both of these modules would take a callback function as an argument.
This callback function takes two arguments, error and result, where error is an error
object returned if the called function fails to complete its task, and result is the object
returned if the called function succeeds. For testing purposes, if no callback function is passed
as an argument, the error object or result object will simply be outputted to the console.
The socketEventHandler.js file in the sockets directory would contain all socket
message and event handlers that handle communication with the client after connection,
hence it will use the query.js module to access or update data in the database upon a
client’s request (i.e. message sent). Fig. 4 illustrates the structure of the server, without
conforming to a particular specification.
FIGURE 4: generic representation of the server structure
13
Although the client-server communication would be done using WebSockets and does not
require the implementation of routes, the fake book application will still use the Express
framework due to the many advantages it offers such as static file serving and middleware.
Using Express also implies that future implementation of new features such as user login and
sessions is made much easier.
Client Structure
A very important aspect of the application when it comes to user satisfaction is a well
designed and efficient front end user interface. In accomplishing this, the design of the fake
book application client side involved the use of Bootstrap, a web development front-end
framework, and the jQuery JavaScript library. To simplify navigation and make data easily
accessible, it was decided that both the book data and song data will appear on one page,
index.html. This page will display two tables, one containing book data and the other
containing song data. To assist with managing the data in both tables, the DataTables plug-in
for jQuery will be used. Since it was previously decided that the client-server communication
method would be implemented using the Socket.IO library, the client API provided by Socket.IO
will be used to implement the message and event handlers for the client side.
14
Implementation
With the completion of the fake book application design, implementation of the application began. This section describes the work that went into the development of the application, starting with the server side and finishing with the client side.
Server
There were multiple tasks that were completed during the development of the server,
all of which were done in order as required. These tasks were the creation and completion of
the database.js module, the query.js module, and the socket message and event
handlers which reside in the socketEventHandler.js file.
Implementation of the server began with the completion of the database.js
module. As indicated in the design, this module would be responsible for the direct
communication with the fake book SQLite database. To help accomplish this, the sqlite3
module for Node.js, which provides an API for accessing SQLite databases, was installed and
used. The database.js module needed to support four database operations: SELECT,
INSERT, UPDATE, and DELETE. To support the SELECT operation, the doSelect function
was created. This function takes two arguments, queryString and callback. The first
argument, queryString, is a string that specifies the portion of an SQL SELECT statement
that comes right after the SELECT keyword. Table 2 lists examples of the queryString
argument and the corresponding result.
TABLE 2: result of passing the given query string as an argument to the doSelect function
Query String Result
“* FROM bookcodes” Selects all books from the bookcodes table
“* FROM songs WHERE id = 1” Selects the song with id 1 from the songs table
15
The second argument, callback, must be a function that takes two parameters, an error
object, and a result object. If the SELECT query fails, the doSelect function will specify the
error in the error object, otherwise, it will return the selected row(s) within the result object, in
the form of an array of objects1. The doSelect function uses the each function from the
sqlite3 module API to complete this task. The each function takes three arguments: the
SQL query string, a callback function cbRowRetrieved for each row retrieved, and a
callback function cbComplete when the query finishes (i.e. callback for every matching row
has been called or if no matching rows were found). Within the cbRowRetrieved callback,
the doSelect function adds each retrieved row to an array. Once the cbComplete function
is called, the doSelect returns this array as the result object within its own callback function.
The next database operations that the database.js module needed to support were
INSERT, UPDATE, and DELETE. The sqlite3 module API provides a function called run
which handles all of these operations. For code reuse purposes, a private function called
runQuery2 was created. This function takes four arguments: queryType, queryString,
placeholderValuesArray, and callback. The first argument, queryType, is a string
specifying the type of query (i.e. insert, update, or delete). The second argument,
queryString, is a string which consists of the portion of an SQL statement that comes after
the keyword for the specified query type (i.e. if the query type is INSERT, then the
queryString argument would consist of a string beginning with “into...”). The third
argument, placeholderValuesArray, is an array containing values associated with
parameterized queries, or in other words, queries that contain placeholders as parameter
values3. If the query specified is not a parameterized query, an empty array is passed. The final
argument, callback, is a callback function. To prevent SQL injection, the runQuery function
first prepares the SQL statement using the prepare function provided in the sqlite3
module API. Once the statement is successfully prepared, the runQuery function calls the
run function that is contained in the sqlite3 module API to execute the prepared
1 Note that in JavaScript, an array is considered a special type of object 2 This function is not exported; hence it is only accessible from within the database.js module itself 3 In SQL, placeholders are identified by question marks
16
statement, returning the result via its callback function. Since the runQuery function is
private and can only be accessed from within the database.js module, three other
public/exported functions called doInsert, doUpdate, and doDelete were created to
execute INSERT, UPDATE, and DELETE SQL statements respectively, using the runQuery
function.
After completion of the database.js module, the next completed task was the
development of the query.js module. This module uses the database.js module to
provide functions that allow the retrieval, insertion, update, and deletion of book and song data
in the database, while abstracting away the SQL logic. The first function created was
getBooks which retrieves book data from the database. The getBooks function takes three
arguments: conditionsSpec, orderBySpec, and a callback function. The first argument,
conditionsSpec, is an object containing conditions placed on the book attributes that must
be satisfied when retrieving the books from the database. These conditions may include a
certain book code, a certain substring or phrase within the book title, etc. An empty
conditionsSpec object implies no conditions. The second argument, orderBySpec, is an
object containing two properties: orderByColumn which is a string containing the column
(book property) to order the retrieved books by, and sort which contains the string asc for
sorting in an ascending fashion, or desc for sorting in a descending fashion. An empty
orderBySpec object implies no specific ordering. The getBooks function uses the
conditionsSpec object to construct the appropriate SQL WHERE clause and uses the
orderBySpec object to construct the appropriate SQL ORDER BY clause. It then constructs
the SQL query string and calls the doSelect function contained in the database.js
module to retrieve the book data from the bookcodes table in the database.
Fig. 5 shows an example of using the getBooks function with a specific conditionsSpec
object and an orderBySpec object.
17
The next function created was getSongs which retrieves song data from the database. The
getSongs function is similar to the getBooks function in that it also takes three arguments,
a conditionsSpec object, a orderBySpec object, and a callback function. The
getSongs function also uses both the conditionsSpec and the orderBySpec objects
to construct the appropriate SQL query string, and then calls the doSelect function
contained in the database.js module to retrieve the song data from the songs table in the
database. In order to retrieve all songs contained in a certain book, the
getAllSongsInBook function was created. This function takes a bookCode as an
argument and passes the appropriate SQL query string to the doSelect function, returning all
songs within the specified book. Two other functions, getBookByCode and getSongById
were also created with the purpose of retrieving a book given a specific book code and
retrieving a song given a specific song id respectively. Both of these functions also use the
doSelect function to run the SQL queries. The next function created was addBook which
inserts a new book into the database. This function takes two arguments, bookObject and a
callback function. The bookObject argument should be an object containing the book’s
FIGURE 5: example of using the getBooks function
18
properties and their respective values. These properties should match the column names in the
bookcodes table in the database which are as follows: code, title, format, filename, and
page_offset. The addBook function constructs a parameterized SQL query string and calls the
doInsert function contained in the database.js module to insert the book into the
database. The next function created was updateBookByCode and its purpose is to update
book data for a specific book. This function takes three arguments: bookCode, bookObject,
and a callback function. The first argument, bookCode, is a string containing the code of the
book to update while the second argument, bookObject, is an object containing a mapping
of the book properties to update and their new values. Using the bookObject, the
updateBookByCode function constructs the appropriate SQL query string and calls the
doUpdate function contained in the database.js module to update the bookcodes
table with the new book data. The function that was completed next was updateSongById
which updates song data for a specific song. This function takes three arguments: songId,
songObject, and a callback function. The songId argument is an integer specifying the
unique id of the song while songObject is an object containing a mapping of song properties
to update and the updated values. The updateSongById function constructs the
appropriate SQL query string and calls the doUpdate function contained in the
database.js module to update the songs table with the new song data. The next function
created was removeBook which deletes a given book from the database. This function takes a
book code as its first argument which specifies the book to delete, and a callback function as its
second argument. The removeBook function constructs the appropriate SQL query string and
calls the doDelete function contained in the database.js module to delete the book data
from the bookcodes table in the database. The removeSong function that was created next
provides the same functionality as the removeBook function but for songs, taking in a song id
as its first argument. Similar to the removeBook function, the removeSong function calls
the doDelete function to delete the song data of the song with the given id from the songs
table in the database. In order to simplify the removal of multiple songs from the database at
once, a removeMultipleSongs function was created. This function takes an array of song
id`s as an argument and loops through this array, removing each song using the removeSong
19
function that was previously created. Through its callback, the removeMultipleSongs
function returns an array containing the song id’s of the songs that were successfully removed
from the database, and a Boolean indicating whether all songs were successfully removed or
not.
With the completion of the library modules database.js and query.js, the next
task involved the development of the socket message and event handlers in
socketEventHandler.js which handle communication with a client. When the server
receives a message from a client for a specific task (i.e. get book data), a function associated with
the event handler for that message on the server is executed, handling the request and sending a
message to the client with the result. Fig. 6 shows how these message and event handlers are
defined.
The development of the event handlers for client requests dealing with the retrieval of book
and song data from the database was done first. For the retrieval of book data, an event
handler for the getBooks message was created. The function associated with the getBooks
event handler takes a spec object4 as an argument. This spec object should contain a
conditions object and an orderBy object. The conditions object corresponds to the
conditionsSpec object passed into the getBooks function in the query.js module
while the orderBy object corresponds to the orderBySpec object. The handling function
for the getBooks message calls the getBooks method contained in the query.js module
to retrieve the books from the database. If the books were successfully retrieved, a
4 This object must be sent by the client along with the getBooks message
FIGURE 6: definition of the socket message and event handlers
20
sentBooks message is sent to the client along with an array containing the retrieved book
data. Otherwise, a sentError message is sent indicating failure. The sentBooks message is
also sent once to a client right after the socket connection is established for initialization
purposes. For the retrieval of song data, an event handler for the getSongs message was
created. The function associated with the getSongs event handler is very similar to that of
the getBooks event handler, with the exception of using the getSongs function contained
in the query.js module rather than the getBooks function. The second step involved the
development of the event handlers which handle client requests that deal with the addition of
new books and songs. This involved the creation of two event handlers, one for the addBook
message, and another for the addSong message. The function associated with the addBook
event handler takes a book object as an argument containing book properties and their values.
This function calls the addBook function contained in the query.js module to insert the
book into the database, sending an addedBookSuccessfully message back to the client
upon success. Similarly, the function associated with the addSong event handler takes a song
object and calls the addSong function contained in the query.js module to insert the song
into the database, sending an addedSongSuccessfully message to the client if
successful. When one client adds a new book or song, other connected clients should be
notified of this new data. To account for this, a bookAddedByAnotherClient and a
songAddedByAnotherClient message is sent to all other connected clients when
another client adds a new book or song respectively. The third step involved the development
of event handlers that handle client requests dealing with the update of existing book or song
data in the database. Two new event handlers were created to handle the updateBook and
updateSong messages. The updateBook event handler function takes a book object as an
argument which should contain the code of the book to update and the properties to update
along with their new values. The handler function then calls the updateBookByCode
function from the query.js module to update the book data in the database. Upon success,
an updatedBookSuccessfully message is sent to the client that initiated the update and
a bookUpdatedByAnotherClient message is sent to all other clients. Likewise, the
updateSong event handler function takes a song object as an argument containing the id of
21
the song to update and the song properties to change along with their new values. It then calls
the updateSongById function from the query.js module to update the song in the
database, sending an updatedSongSuccessfully message to the client that initiated the
request and a songUpdatedByAnotherClient message to all other clients upon success.
Finally, two more event handlers were created to handle client requests for the removal of data
from the database. One of these event handlers handles the removeBook message. The
function associated with this handler takes a book code as an argument and calls the
removeBook function from the query.js module to delete the book data from the
database. If the book was successfully removed, a removedBookSuccessfully message is
sent to the client that initiated the request and a bookRemovedByAnotherClient
message is sent to all other clients. The other created event handler handles the
removeSongs message. The function associated with this event handler takes an array
containing the song id`s of the songs to remove and calls the removeMultipleSongs
function contained in the query.js module to delete the specified songs, sending a
removedSongsSuccessfully message to the client that initiated the request and a
songsRemovedByAnotherClient message to all other clients.
Client
Development of the client involved the creation of one static webpage, index.html.
Work on index.html consisted of the creation of the user interface, the creation of the
socket message and event handlers which are responsible for handling communication with the
server, and finally creating the event handlers for the user interface elements to handle user
interaction.
The initial design of the client user interface involved the creation of two tables, one
containing book data, and another containing song data. Both tables would be managed using
the DataTables jQuery plug-in. To create the initial skeleton of the tables, the HTML table tag
22
was used. The book table and song table are both identified by their unique id attributes,
bookTable and songTable respectively. The book table has six columns and each row of
the table corresponds to a specific book. The first five columns consist of the following book
properties: code, title, file name, format, and page offset. The last column contains two
buttons, one that allows the user to edit the book data for the book in the corresponding row
and another button to remove that book from the database. Above the book table to the right
side, a search bar was created to allow users to search for books based on code, title, file name,
or format. Above the search bar, an “Add Book” button was created to allow users to add a new
book. The song table has six columns. For each row corresponding to a song, the first column
contains a checkbox which is checked when that row/song is selected. The header cell for this
column contains a button which allows a user to remove all the selected songs at once. The
second to fifth columns consist of the following song properties respectively: id, title, page, and
book code. The last column contains a button which allows the user to edit the song data for
the song in the corresponding row. Above the song table to the right side, a search bar was
created to allow users to search for songs based on title. Above the search bar, an “Add Song”
button was created to allow users to add a new song.
Multiple functions were created for the purpose of sending requests to the server. Each
of these functions is responsible for sending a message to the server to retrieve, update, insert,
or delete book or song data from the database. For each of these functions, a corresponding
function has been created to handle the response from the server. For example, the
sendGetBooksRequest function sends a getBooks message to the server while the
handleSentBooks function handles the response from the server (the sentBooks
message) by displaying the books in the book table. Table 2 provides a list of all of these
functions, their purpose, and their corresponding server response handler functions.
23
TABLE 3: name of each client request function, its purpose, and the name of its corresponding server response handler function
Request Function Purpose Response Handler Function
sendGetBooksRequest Sends the getBooks message to the server to retrieve book data
handleSentBooks
sendGetSongsRequest Sends the getSongs message to the server to retrieve book data
handleSentSongs
sendAddBookRequest Sends the addBook message to the server along with the new book data to insert into the database
handleAddedBookSuccessfully
sendAddSongRequest Sends the addSong message to the server along with the new song data to insert into the database
handleAddedSongSuccessfully
sendUpdateBookRequest Sends the updateBook message to the server along with the updated book data
handleUpdatedBookSuccessfully
sendUpdateSongRequest Sends the updateSong message to the server along with the updated song data
handleUpdatedSongSuccessfully
sendRemoveBookRequest Sends the removeBook message to the server along with the code of the book to remove
handleRemovedBookSuccessfully
sendRemoveSongsRequest Sends the removeSongs message to the server along with an array containing id’s of songs to remove
handleRemovedSongsSuccessfully
24
Furthermore, multiple other functions containing event handlers were created to handle
messages sent from the server regarding the modification of data by other connected clients.
One of these functions is handleBookAddedByAnotherClient which contains an event
handler for the bookAddedByAnotherClient message sent by the server. The event
handler function uses the book object received from the server to add the new book to the
book table. Another function is handleBookUpdatedByAnotherClient which contains
an event handler for the bookUpdatedByAnotherClient message. The event handler
function uses the updated book object received from the server to update the book data and
redraw the table. One other function is handleBookRemovedByAnotherClient which
contains an event handler for the bookRemovedByAnotherClient message sent by the
server. The function associated with this event handler uses the code of the removed book,
sent by the server, to delete the corresponding row/book and redraw the table. Similar to the
previous functions mentioned but with respect to song data, the
handleSongAddedByAnotherClient, handleSongUpdatedByAnotherClient,
and handleSongsRemovedByAnotherClient functions contain event handlers for the
songAddedByAnotherClient, songUpdatedByAnotherClient, and
songsRemovedByAnotherClient messages respectively. Along with the mentioned
functions related to the socket event handling, a function called handleError was created to
contain the event handler for the sentError message that is sent by the server if an error
occurs. The function associated with this event handler simply indicates failure to complete a
request by displaying an appropriate error message. After socket connection is established, the
server sends a sentBooks message along with an array of books. The handleSentBooks
function contains the event handler for this message. The function associated with this event
handler is executed, initializing the book table using the DataTables constructor function
$(‘#bookTable’).DataTable() where “bookTable” is the id of the book table. The
DataTable constructor takes an object specifying multiple options or properties pertaining to
the table. One of the properties used, called data, specifies the initial data to fill the table
with, which in this case was the books array that was received from the server. Another
property that was used was createdRow. The value of the createdRow property is a
25
function which is called after a row, identified by the tr tag in HTML, has been added to the
table. This function sets the id attribute of each row (i.e. tr tag) to row-book-<code>
where <code> refers to the code of the book corresponding to that row. This uniquely
identifies every row in the table, making it easier to execute an operation on a specific
row/book. For the song table, the id attribute of each row is set to row-song-<id> where
<id> is the song id. After the book table is initialized, the first row/book in the table is selected
and a request is sent to the server to retrieve the songs contained in that specific book, using
the sendGetSongsRequest function. Once the songs are received, the song table is
initialized.
Using jQuery, event handlers were attached to the user interface elements to handle
user interaction. Clicking on a row in the book table selects the row/book and the
sendGetSongsRequest function is called to retrieve the songs contained in that book. The
song table is then redrawn with the retrieved song data. Clicking on the edit book button
launches a modal window containing fields corresponding to editable book properties. The
modal window contains a “Save” button which has an event handler function attached to it for
the click event. When the “Save” button is clicked, its event handler function is executed, calling
the sendUpdateBookRequest function to update the book data. Clicking on the remove
book button launches a confirmation modal window which contains a “Remove” button. The
click event handler function for the “Remove” button calls the sendRemoveBookRequest
function to send a request to the server to remove the selected book from the database.
Similar to the edit book button, a click on the edit song button launches a modal window
containing editable fields, allowing the user to edit the song data. This modal window also has a
“Save” button which, when clicked, will trigger its event handler function which in turn sends an
update song request to the server using the sendUpdateSongRequest function. When it
comes to the remove songs button, clicking on it will result in the launching of a modal window
containing a confirmation message and a “Remove” button. This “Remove” button has a click
event handler attached to it which, when triggered, will loop through all the selected songs in
the song table and add their song id’s to an array. It then sends a song removal request to the
26
server by calling the sendRemoveSongsRequest function. Two other buttons, add book
and add song have click event handlers attached to them which launch a modal window
containing empty fields for specifying new book and song data respectively. The modal window
in both cases contains a “Save” button which, when clicked, will trigger its click event handler
which in turn calls the sendAddBookRequest if the user is adding a new book or the
sendAddSongRequest if the user is adding a new song. A very important aspect of the
application is the capability of searching book and song data. To make the search bar in the
book table functional, a click event handler was attached to the “Search” button. This event
handler uses the string entered by the user in the search field to create the appropriate
conditions object and calls the sendGetBooksRequest function to retrieve the books
that match the specified conditions. Likewise, the “Search” button for the song table’s search
bar has a click event handler attached to it which calls the sendGetSongsRequest to
retrieve songs that have a title matching that of the search string.
27
Results The end goal of this project, the development of a Node.js-based web application for
managing fake book index data, was accomplished. Through the multiple stages of
development which included the design and coding, both the server and client side of the
application were completed. The server, which handles requests to retrieve, insert, update, and
remove book and song data in the database, was developed with clarity and simplicity in mind.
This would not only allow easier understanding of functionality if this application was to be
used for educational purposes (i.e. as a basis for course assignments) but would also ease the
implementation of new features in the future. The client was developed with user satisfaction
in mind. An easy to use and efficient user interface was one of the top priorities. Fig. 7 shows
the user interface of the book table while Fig. 8 shows the user interface of the song table.
FIGURE 7: the user interface of the book table
28
Communication between the client and server was implemented using WebSockets to allow for
real-time communication, efficiently handling the simultaneous access of data in the database
by multiple clients. This Node.js-based application would benefit any person who makes use of
fake book index data.
FIGURE 8: the user interface of the song table
29
Conclusion
This report described in detail the development of the Node.js-based fake book web
application from design to implementation. Development involved the creation of a functional
server that provides access to the data contained in the fake book indexing database and a
client side that provides an efficient and easy to use user interface for the end user. In the
future, this application can be used as a basis for assignments in the databases course that is
offered at Carleton University. Furthermore, this application can be extended to provide more
functionality such as supporting user login, allowing users to upload files containing copies of
fake books, displaying chord charts for songs, and allowing users to upload an audio file
pertaining to a particular song. By updating the current fake book indexing database and adding
such features to this fake book web application, music students and teachers would find such
application even more useful in managing the fake books that they rely on as a source of songs.
30
References Gupta, A. (2014, February 24). REST vs WebSocket Comparison and Benchmarks.
Retrieved from http://blog.arungupta.me/rest-vs-websocket-comparison-benchmarks/ West, M. (2013, October 18). An Introduction to WebSockets. Retrieved from
http://blog.teamtreehouse.com/an-introduction-to-websockets Express – Node.js web application framework. (2016). Retrieved from
http://expressjs.com/ jQuery.ajax(). (2016). Retrieved from http://api.jquery.com/jquery.ajax/
WebSockets. (2016). Retrieved from https://developer.mozilla.org/en-
US/docs/Web/API/WebSockets_API RESTful Web Services – Statelessness. (2016). Retrieved from
http://www.tutorialspoint.com/restful/restful_statelessness.htm