XCoins code review repository.
First install the dependencies:
npm iBuild the project. (Using TypeScript3)
npm run buildWatch for changes and rebuild automatically.
npm run build:watchTest the project. (Using Jest4)
npm testTest with code coverage report.
npm run test:coverageTest in ci.
npm run test:ciCheck for code style issues in the project. (Using ESLint5)
npm run lintFix code style issues in the project.
npm run lint:fixFirst create the .env file:
cp .env.example .env| Name | Type | Default | Description |
|---|---|---|---|
NODE_ENV |
production,development,test |
development |
Node.js environment (test will be provided by the testing framework automatically) |
| Name | Type | Default | Description |
|---|---|---|---|
SERVER_PORT |
integer | 3000 |
Express.js server port |
CORS_ORIGINS |
string | http://localhost:3000 |
Comma separated list of acceptable origin servers |
| Name | Type | Default | Description |
|---|---|---|---|
DATABASE_URI |
string | - | MongoDB connection string uri |
| Name | Type | Default | Description |
|---|---|---|---|
SENTRY_DSN |
string | - | Sentry project DSN value |
Start the API.
npm startWatch for changes and restart automatically.
npm run devStart the Docker6 compose services:
docker-compose up -d --build --remove-orphansStop the docker compose services:
docker-compose downGenerate the Code documents to be served statically. (Using TypeDoc7)
npm run docs:codeAfter running this command, open docs/code/index.html in your preferred browser.
Generate the API documents to be served statically. (Using Swagger8)
npm run docs:swaggerGenerate & serve the API documents. (The documents' server address will be printed in the terminal)
npm run docs:api.
├── .build # Project (TypeScript) build directory
├── __tests__ # Test files
│ ├── controllers # API controller integration tests
│ ├── jest # Test utilities
│ ├── lib # Library unit tests
│ └── utils # Utility unit tests
├── docs # Static documents
│ ├── api # API documents
│ └── code # Code documents
├── scripts # Project scripts
└── src # Source files
├── constants # Constant values
├── controllers # API controllers
├── lib # 3rd party libraries (initialized/extended etc)
├── models # Database models
├── routes # API endpoints
└── utils # Utilities
Note:
__mocks__directories are used byJestto mock certain modules.
This project uses SemVer9 for versioning. For the versions & changelogs available, see the releases on this repository.
This section includes the issues, changes & improvements I've made, with the thought process (explanation) behind them.
- No unit/integration tests.
- Missing documents.
- No usage document is provided in the
README.mdfile. - No comments or documents are provided for the project. (e.g.
jsdoc,tsdoc,typedoc) - No API documents are provided for the project. (e.g.
swagger)
- No usage document is provided in the
- No API authentication implemented.
- Missing
.gitignorefile.Could cause unintended files to be pushed to the
gitserver accidentally. - Issues related to
package.json:- Missing
package-lock.jsonfile.Without the
package-lock.jsonfile, we can't keep track of the installed dependencies, meaning there could be completely different versions of each package installed on each developer machines and the production server. This could cause problems both in development & production environments as it makes it difficult to debug & avoid possible incompatibility & security issues in dependencies. - Missing
"private": trueproperty:This property will avoid accidental publication of the repository.
mainproperty pointing to a non-existing file.devDependenciesbeing wrongly included independencies:This will result to unnecessary packages being installed in the production server. This can increase production project size (e.g. Docker image). Related dependencies:
@types/cors,@types/express,@types/express-handlebars,ts-node,ts-node-dev,typescript- Unused dependencies.
Related dependencies:
chart.js,express-handlebars,lodash,luxon,@types/express-handlebars,eslint-plugin-react,ts-node - Outdated dependencies.
Related dependencies:
body-parser,dotenv,express,mongoose,@types/cors,@types/express,@typescript-eslint/eslint-plugin,@typescript-eslint/parser,eslint,ts-node-dev,typescript - Not using exact versions for dependencies.
This issue has somewhat similar effects as the
package-lock.jsonissue, as^versionwill allow any semver compatible version to be installed.
- Missing
- Missing
eslintconfig.The
eslintconfig allows to enforce the desired code style among all the contributors. - Issues in the
srcdirectory:- Unused imports. (e.g. unused
lodashimport in thesrc/scripts/seed.ts) - Wrong values passed to the database models to be created based on the provided database model schemas.
(e.g.
name,start_date,check_date,divisa,Crypto_price_start&Crypto_price_checkfields for theSimulatormodel in thesrc/scripts/seed.tsfile) - Using
varto define variables.This way the variable would be defined/redefined globally which could cause problems. Instead of
var, it's best to useletorconst. - Database models weren't typed.
I added the missing interfaces that can be modified easily if needed.
- Database model fields were all optional & lacked the information about other required validations.
- Database model fields lacked consistency. (e.g. some used
snake-caseformat & somecamel-casesuch asdateRecordedin theSimulatormodel) - Monetary values were stored as
Numberin the database.This can cause problems as it doesn't have precision safety required to do the math. I used
Decimal128as suggested in this officialMongoDBdocument. For mathematical calculations in the project we can use bignumber.js, to handle the precision appropriately. - Unused/Redundant usage of
express()&cors()in thesrc/routes/simulator.router.tsfile. - Redundant
/apiprefix used in the routes. I instead used a more useful/v{major}prefix. (/v1)Using
/v{major}route prefix allows to possibility of deploying breaking changes without loosing backward compatibility. - Unuseful
console.logusage. for logging purposes, it's better use a proper logging library or service such asSentry. - Inconsistent API response format.
Some controllers directly send the database record(s) as the response, some send them wrapped inside an object.
- No request validation was in place for any of the controllers.
- The
seedscript was creating a database records using different fields than the fields in the models. ( e.g.Simulatorrecord) - The
seedscript was not awaiting database connection/disconnection.
- Unused imports. (e.g. unused
- Added
Dockerfile&docker-compose.yml.The
docker-compose.ymlwill be used for development environment, so that the developers won't have to set up the dependant services. TheDockerfilewill be used for production deployment. (e.g. Kubernetes) - Improvements related to
TypeScript:- Changed
targetfromes5toesnextto avoid polyfill overhead & possibly improve performance. - Changed
outDirfromdistto.buildas it's not supposed to be manually modified. (personal preference) - Enabled
incrementalto improve build times. - Enabled
removeCommentsto avoid emitting comments unnecessarily & improve production size (Very small improvement, but still an improvement 😁). - Enabled
inlineSourcesto improve source mapping for usage in services such asSentry. - Added
pathsto improve code quality and avoid long relative imports.for this purpose, I used
importsproperty inpackage.jsonto avoid using unnecessary third-party application, which improves both the startup time and security, due to the fact thatNode.jswill only apply these path aliases to the current package, meaning no installed dependency can use these path aliases (which could cause security issues as well)
- Changed
- Improvements in the
srcdirectory:- Added the
src/models/index.tsfile to provide easier & cleaner access to all database models throughout the entire project.I didn't use
export defaultfor the models, because in theindex.tsI wanted to be able to easily useexport * from "some-model". - Added the
src/constantsdirectory to move all constant values there instead of being scattered all over the project.This ensures that the project is using the same consistent values everywhere.
MODEL&COLLECTIONconstants are also added, due to the fact that they can be useful in scenarios such as$lookupaggregation stages. Also In case of need to change the said values, it just needs to be updated in one places only. - Added the
src/routes/index.tsfile to provide cleaner api endpoint management.I exported the routes as
defaultin this case, due to only having one job, which is exporting the expressRouter. - Renamed the router filenames. The
.routerpart of the name was redundant, since they're already under theroutesdirectory. - Moved the controllers to the
controllersdirectory & each controller to be in a separate file.This makes code cleaner and easier to maintain. not the directory
routesonly manages the routing & thecontrollersdirectory manages route behaviors. By putting controllers in separate files, it will become easier to detect which dependencies are used in which controller and the number of controllers won't affect the readability of the code, thus easier to improve, debug & maintain. - Added the
wrapControllerutility.expressdoesn't catch async errors properly, so I added this utility to wrap the controllers before passing them to theRouterinstance. - Added pagination to the endpoints that were listing records.
- Added
Sentryto track issues in the production environment. - Added graceful shutdown.
- Configured CI/CD using GitHub Actions.
- Added the