Goal | References | Quickstart | Run in Docker | Run on machine directly | Development methodology | Routes | Package layout | Production usage | Tests | Dependencies
Provide a REST API server that can convert decimal integers (e.g. 1, 10, 100, 200) into the roman numeral equivalent. The server offers a route of type http://localhost:8080/romannumeral?query=10 to do so, in which query is holds the value of the integer to convert.
Two resources describe the rules the server will follow for conversions of decimal integers to roman numbers:
-
For roman numerals: Roman Numerals on mathisfun
-
For syntax additions to handle large roman numbers: Roman Numerals for large numbers
Prerequisite: Needs to have Docker installed.
You can build and run the server immediately by running the docker-compose file at the root of the project.
Per default, the server will be listening on port 8080.
From the root of the project, to run in background:
docker-compose up -d
Once it is running, you can try out the server by doing curl http://localhost:8080/romannumeral?query=42
(or click http://localhost:8080/romannumeral?query=42).
To shutdown the server, from the root of the project run:
docker-compose down
Prerequisite: Needs to have Docker installed.
This project can be run inside a Docker container.
To do so, from the root of the project, you first need to build the Docker image:
docker build . --tag localhost:romannumeral
Then, to run a container based on the built image in background with the server listening on port 8080:
docker run -d -p 8080:8080 localhost:romannumeral
Or to run a container based on the built image in foreground with the server listening on port 8080:
docker run -p 8080:8080 localhost:romannumeral
Prerequisite: Needs NodeJS version 10.16.0 or higher installed.
You will need to install the dependencies first. From the root of the folder:
-
For usage in a dev/test environment:
npm i
-
For production use:
npm i --only=production
Then, from the root of this project, run: npm start
The first step is to get a good grasp of the requirements and edge cases. Here, we want to convert a decimal integer to a roman numeral. Edge cases occur if we go outside of the supported limits for conversion. Also, the case where the value to convert is 0 is handled as a special out-of-range edge case to signal this error to clients, since there is no 0 in the roman number system (contrary to the current decimal system).
The development of this server is incremental and in successive small steps: functionalities are added, improved and refactored over time in iterations. This is very similar to the Scrum Agile methodology. Each commit is a small unit of work. Also, it is possible to work incrementally because the functionalities are unit-tested: the impact of changes can be quickly identified through the passing/failing tests. Using this, the process is: write unit test > develop and make code pass the test > refactor > run tests (potentially repeating last 2 steps).
The first milestone was to get a base working version (integer to roman conversion) to get a minimum viable product (server that converts numbers from 0 to 255 to romannumeral and returns errors for error cases). Then, extend and improve business functionalities (extend supported range of values for conversions).
In parallel, also work on configurability, monitoring and logging capabilities (non-functional requirements). The second milestone was to get this web program containerized for easier deployment.
All functionalities must be unit tested, especially those used to do the roman numeral conversion (since they are of critical value for this server). Also, integration tests need to be written for added routes and functionalities, to verify that the server is capable of responding to requests as expected.
To finish, REST API routes need to be documented in the project's swagger file. Code must also be documented inline using JSDoc format.
Detailed route documentation can be found in the swagger file in the project folder api-documentation.
The route is of the general form http://host/romannumeral?query={integer}, where query contains the integer to convert.
Example when running on localhost: http://localhosthost/romannumeral?query=50
This route takes a decimal integer as parameter. If the query parameter is within convertible ranges, the server responds with HTTP status code 200 and a json object containing the roman number equivalent (value is in UTF-8 for large numbers):
{ "roman" : "your_converted_value"}
The server will return a HTTP status code 422 and a json object describing the error:
{
"error": "OUT_OF_RANGE",
"message": "Parameter is not within range",
"details": { "lowerLimit": min_accepted_value, "upperLimit": max_accepted_value}
"apiVersion": "apiVersion"
}
Note: An out of range error will be returned for negative values, since roman numbers do not have negative values.
Setting query parameter to 0 will return an error, since 0 is out of the supported range. Since there is no 0 in the roman counting system. As additional information for the caller, this will produce an error telling that the query value was out of range and 0.
The server will return a HTTP status code 422 and a json object describing the error:
{
"error": "VALUE_IS_ZERO",
"message": "Parameter value is 0, roman numbers do not have a 0. Zero is out of supported range for conversions. Smallest supported value is 1.",
"details": { "lowerLimit": min_accepted_value},
"apiVersion": "apiVersion"
}
The server will return a HTTP status code 422 and a json object describing the error:
{
"error": "NOT_AN_INTEGER",
"message": "Parameter is not an integer",
"apiVersion": "apiVersion"
}
In case the server is busy and cannot respond to more requests, it will start sending back HTTP status code 503.
If the server is up and running, a request sent to http://your_host/heartbeat will make the server respond with a HTTP status code 200. There is no response body.
No response/timeout means that the server is not running or is in a crashed state.
If the server is up and running, a request sent to http://your_host/version will make the server respond with a status 200 and a json object containing the version of the romannumeral API currently used:
{ "apiVersion": apiVersion }
If a request is made to the server using an unknown route, HTTP status code 404 is returned.
Folders at root of this project:
-
api-documentation: contains the swagger file documenting the REST API.
-
monitoring: contains code to handle logging.
-
roman-umber-handlers: contains the code files necessary to do the roman conversion (also error handling code).
-
routes: contains the routes defined and used by the API server.
-
test: contains tests (unit tests and integration tests).
Files at root of the romannumeral API server project:
-
settings.env: default values for some environment values.
-
config.js : configures environment for the server (reads settings.env and sets up middlewares).
-
docker-compose.yml: file to build and run the API server in a Docker container.
-
Dockerfile: file to build the Docker image for this project.
-
package.json:manifest file containing metadata about this project.
-
package-lock.json: locked project dependencies.
-
server.js: file containing code for the server.
-
license.txt: license file.
At runtime, and additional folder "logs" holds log files.
Note: Folder api-documentation is not made available through the API server when the server is running (avoids leaking information about the server).
Currently, only HTTP is supported out of the box. For HTTPS, please use a proxy (like NGINX) in front of this server.
Tests are available in the test folder.
There are two kind of tests available currently in this project:
-
some testing the conversion functionality without the server capabilities (unit tests).
-
some testing the API server and its routes (integration tests).
To run all the tests, from the root of the project, run:
npm test
Troubleshooting: You may need to install mocha globally to run the tests (npm i mocha -g).
Tests also run automatically during the build of a Docker image for this project.
The web server is an express.js webserver (Express website, Express Github).
The server uses some middlewares for an enhanced experience:
-
cors, to enable Cross-origin_resource_sharing,
-
node-toobusy, to notify clients if the server is busy,
-
express-slow-down, a rate-limiter,
-
helmet, to add security by setting some HTTP headers,
-
hpp, to avoid query parameter pollution.
To read environment files and configure the server to use them, there is a dependency to dotenv.
Finally, for logging the server uses the express morgan middleware for console logging and winston to save logs into files.
This project has test dependencies: chai, mocha and supertest.
Also, a lot of test cases where inspired by the big-list-of-naughty-strings.
First-level dependencies and development dependencies bring their own dependencies with them.
Github provides a dependency graph listing all dependencies (first level and their dependencies).
Next steps would be to:
-
add support to send metrics to Prometheus,
-
automate test run when a pull request is opened,
-
if some numbers are more transformed than other, add LRU caching,
-
depending on usage and usage feedback, add scaling using Node's clustering capabilities.
No publicly accessible demo is deployed for the romannumeral server. To try it out: Quickstart.