./index.js
./src/server.js
./src/api/v1.router.js
./src/api/v1.events.js
./src/api/command-handlers/about.js
./src/api/command-handlers/details.js
./src/api/command-handlers/fallback.js
./src/api/command-handlers/help.js
./src/api/command-handlers/join.js
./src/api/command-handlers/launch.js
./src/api/command-handlers/leave.js
./src/api/command-handlers/me.js
./src/api/command-handlers/msg.js
./src/api/command-handlers/nick.js
./src/api/command-handlers/room.js
./src/api/event-handlers/handle-command.js
./src/api/event-handlers/handle-connection.js
./src/api/event-handlers/handle-disconnect.js
./src/api/event-handlers/handle-input.js
./src/api/event-handlers/handle-message.js
./src/api/lib/handler-finder.js
./src/api/lib/population-manager.js
./src/api/lib/population.js
./src/api/lib/send-to-room.js
./src/api/lib/send-to-user.js
./src/middleware/404.js
./src/middleware/500.js
./src/middleware/model-finder.js
./src/models/model.model.js
./src/models/app-info/app-info.model.js
./src/models/app-info/app-info.schema.js
This is the entry point of the application. When the app starts, the database and Socket.io connections are initiated.
This module instantiates the app, sets middleware, routes, and controllers, and exports an app
, server
and start
method for the combined Express/Socket.io server.
This module exports an Express router
with dynamic endpoints that correspond to the model
instance determined by the modelFinder
module from ./src/middleware/model-finder.js
. Most routes (except /
) invoke a REST method that manipulates the model
's class methods using the data provided to the endpoint in the request as arguments.
GET
/
→ Returns a short welcome message./api/v1/:model
→ Returns allmodel
records from the database./api/v1/:model/:name
→ Returns amodel
record from the database that has the givenname
; expects aname
parameter.
POST
/api/v1/:model
→ Creates a newmodel
record in the database; expects a JSON object corresponding to themodel
schema in the request body. This route requires thecreate
capability.
PUT
/api/v1/:model/:id
→ Modifies amodel
record in the database; expects anid
parameter and a JSON object corresponding to themodel
schema in the request body. If a record with thatid
does not exist, one is created. This route requires theupdate
capability.
PATCH
/api/v1/:model/:id
→ Modifies amodel
record in the database; expects anid
parameter and a JSON object corresponding to themodel
schema in the request body. No new records will be created. This route requires theupdate
capability.
DELETE
/api/v1/:model/:id
→ Deletes amodel
record in the database that has the givenid
; expects anid
parameter. This route requires thedelete
capability.
This module handles the Socket.io events connection
, input
, and disconnect
, rerouting each to appropriate suites of handling functions.
about(undefined, socket, io)
→ calls sendToUser
at ./src/api/lib/send-to-user.js
with a preset message
and the socket
and io
arguments it has received.
details(undefined, socket, io)
→ calls sendToUser
at ./src/api/lib/send-to-user.js
with a message
derived from queries to the in-memory population store at ./src/api/lib/population.js
along with the socket
and io
arguments it has received.
fallback(undefined, socket, io)
→ calls sendToUser
at ./src/api/lib/send-to-user.js
with a preset message
and the socket
and io
arguments it has received.
This function is invoked when the user enters an invalid command.
help(undefined, socket, io)
→ calls sendToUser
at ./src/api/lib/send-to-user.js
with a preset message
and the socket
and io
arguments it has received.
join(arg, socket, io)
→ Updates the user's room in the in-memory population store at ./src/api/lib/population.js
. Calls sendToUser
or sendToRoom
, as well as the Socket.io methods socket.join
and socket.leave
, as appropriate, with descriptive messages, when a user attempts to join a room.
launch(undefined, socket, io)
→ calls sendToUser
at ./src/api/lib/send-to-user.js
with a preset message
and the socket
and io
arguments it has received.
This function is called when launch
is entered in the client application without an appropriate url
argument.
leave(undefined, socket, io)
→ calls sendToUser
or sendToRoom
, as well as the Socket.io methods socket.join
and socket.leave
, as appropriate, with descriptive messages, when a user attempts to leave a room to return to the chat lobby.
me(arg, socket)
→ calls sendToRoom
with the user's emote arg
, room
, and socket
.
msg(arg, socket, io)
→ calls sendToUser
to a user specified by the first word of the arg
--the rest of the arg
is sent as the message--along with the passed socket
and io
. If the intended recipient does not exist, a message is sent to the sender instead.
nick(arg, socket io)
→ Updates the user's username in the in-memory population store at ./src/api/lib/population.js
. Calls sendToUser
and sendToRoom
with templated messages to provide appropriate updates.
room(arg, socket io)
→ Updates the user's room in the in-memory population store at ./src/api/lib/population.js
. Calls the Socket.io methods socket.join
and socket.leave
as appropriate. Calls sendToUser
and sendToRoom
with templated messages to provide appropriate updates.
handleCommand(line, socket, io)
→ This function uses the parse
and handlerFinder
helper functions to process commands from the user and handle them with the appropriate command handling function.
handleConnection(socket, io)
→ This function uses a setGreeting
helper function to provide an appropriate response when a user signs on.
handleDisconnect(line, socket, io)
→ This function cleans up the in-memory store and provide an appropriate response when a user disconnects.
handleInput(line, socket, io)
→ This function accepts all user input and directs it either to handleCommand
or handleMessage
with the appropriate arguments depending on whether it starts with a /
.
handleMessage(line, socket)
→ This function calls sendToRoom
with the appropriate arguments when a user types a non-command message.
handlerFinder(cmd)
→ Requires an approprate module based on the cmd
argument; reverts to a fallback module on error.
This class contains all of the memory management methods the application uses to keep track of its users and their locations within rooms.
An instance of the Population
class from ./src/api/lib/population-manager.js
.
sendToRoom(message, room, socket)
→ Creates a Socket.io output
event to the appropriate room with the given arguments.
sendToRoom(message, socket, io, id)
→ Creates a Socket.io output
event to the user with the given id
with the given arguments. If no such user exists, the message is directed to the user who initiated the input.
Unknown path fallback middleware.
Server error handling middleware.
This module dynamically evaluates the model
the v1
API will use to invoke REST methods in response to various requests to its routes. The model
is determined by the :model
parameter on requests to /api/v1/:model/*
.
The model is expected to be an instance of a class that extends the ModelClass
from ./src/models/model.model.js
. It is expected to have get
, post
, put
, patch
, and delete
methods.
In this application, AppInfo
model is used at ./src/models/app-info/app-info.model.js
.
This module exports a ModelClass
class that can be instantiated with a Mongoose schema. It has the following methods:
get(name)
→ If aname
argument is provided, this method will return a Promise that resolves to an array containing matching objects. If noname
argument is provided, this method will return a Promise that resolves to an array of all the collection's records.post(obj)
→ This method takes a record object and returns a Promise that resolves to the posted record, which has been added to the database.patch(id, obj)
→ This method takesid
andobj
arguments and updates a record with the givenid
with theobj
in the collection. No new records will be created. The method returns a Promise that resolves to the updated record.put(id, obj)
→ This method takesid
andobj
arguments and updates a record with the givenid
with theobj
in the collection. If an object with the givenid
does not exist, it will be created. The method returns a Promise that resolves to the updated record.delete(id)
→ The method takes anid
argument and returns a Promise that resolves to the deleted record.
This is an example module to demonstrate how models are dynamically incorporated into the API Server. In the ./src/models/
directory, a directory with the name {model}
(here, app-info
) was created. Inside the directory is a file named {model}.model.js
(here, app-info.model.js
) that extends the ModelClass
from ./src/models/model.model.js
.
In this case, the AppInfo
model extends the appInfoSchema
schema at ./src/models/app-info/app-info.schema.js
.
Because the app-info
model has been incorporated into this folder, its methods will be accessible via the endpoint routes. E.g., /api/v1/app-info
is a valid instance of /api/v1/{model}
.
This module defines a mongoose schema appInfoSchema
with the following properties:
name: { type: String, required: true },
description: { type: String, required: true },
url: { type: String, required: true },
MONGODB_URI
- URL to the running mongo instance/dbPORT
- Port number
- Start a MongoDB database on your local machine that uses the
data
folder. - Start the server on your local machine with
npm run start
ornpm run watch
. - Ensure you have appropriate environmental variables set.
See the above documentation on the v1.router.js
for details. For the sake of an example, you can GET
all the records in the app-info
collection with the following command to httpie
:
http :3000/api/v1/app-info
You can POST
a new application to the collection with:
echo '{"name":"Demo", "description": "A good app", "url": "https://www.demo.com"}' | http post :3000/api/v1/app-info
-
How do you run tests?
npm run test
npm run test-watch
npm run lint
-
What assertions were made? Nearly 100 assertions were written. Of those, 73 are complete and passing, yielding a coverage of 87% of lines for all files in the application.
-
What assertions need to be / should be made? Some additional testing of command functions and general Socket.io integration mocking would be in order.
Link to an image of the UML for your application and response to events