-
Notifications
You must be signed in to change notification settings - Fork 3
Project structure
A proper project structure is important, as it creates guidelines to:
- where certain types of files are created.
- naming conventions
- other global conventions throughout the project
And thus, make it easy understandable for everyone, someone new should not have a hard time knowing where to search for a certain file, it should be obvious.
The index.js is located in the root of the folder, this is also the script that should be run to start the application. It is also the script that will run when doing npm start
.
Exports and imports use the Common-JS approach, if this is something you think should change, please create a issue about it.
The rest of the application is located in the src folder. Here are the different sub-directories in this project, and explained what they contain.
Config files are used to declare static config-related strings and variables, used throughout the app.
For example, auth.config.js exports variables like the jwtSecret, this way this static variable is easily accesible throughout the project.
File naming: config files should always be named as following: [uniqueName].config.js
.
Controllers are used to handle requests, they consist of multiple functions that handle requests.
Controllers will communicate with services, and use them to handle logic, while the controller handles getting parameters from the request, and sending the correct response.
File naming: controllers should always be named as following: [uniqueName].controller.js
.
Middlewares are used for checks when a request happens. For example, checking if a user has a specific role.
Middlewares contain multiple functions, that can be used as checks for a request. These functions will be called in the routes, as they are the ones who get the request.
File naming: middlewares should always be named as following: [uniqueName].middleware.js
.
The middlewares sub-directory exists of a index.js file, this file is just there to cleanup the import of middlewares.
It's like a central file, in which all middlewares are stored, and make it easy to access. We also only need 1 import, even if we use multiple middlewares.
It's called index.js
so that the import of this file can just be it's root folder, now the imports can be done as:
+ const middlewares = require('./src/middlewares');
+ middlewares.verifySignup // Now we can access verifySignup like this
- const verifySignup = require('./src/middlewares/verifySignup.middleware');
The models export a mongoose model, as well as an optional 'init' function, that is used to populate the database for a first-startup.
File naming: models should always be named as following: [uniquename].model.js
.
The middlewares sub-directory exists of a index.js file, this file is just there to cleanup the import of models. Aswell as handle some database stuff.
an 'init' function exists aswell, which is used to populate the database on first-startup.
The routes import express, so it can create a router.
const express = require('express');
const router = express.Router();
They can then use that router to make new endpoints in the application.
router.post(
'/signup', // URL
[
verifySignup.checkDuplicateUsernameOrEmail,
verifySignup.checkRolesExist
], // MIDDLEWARE
authController.signup // FUNCTION TO CALL
);
We specify the url of the endpoint, the middleware it should use when a request happens on this endpoint, and the function that should be called when a request happens at this endpoint.
That last parameter, the function, is just a function from the controller.
File naming: routes should always be named as following: [uniquename].routes.js
.
Services are the business layer of the app, this is where we run functions, like 'sign in' or 'registerUser', etc...
File naming: services should always be named as following: [uniquename].service.js
.
In the root directory, there's sub-directory called "test". In here, all the tests are stored.
The main test file here, is app.test.js. In this main test file, we do all the database configuration for testing.
At the bottom of this page, we import the tests from the other test files as follows:
// **********TESTS**********
describe("Services", () => {
describe("authService", authServiceTest.bind(this));
});
We make a new "describe" block for each type of file (service, controller, etc...). In here, we make another "describe" block for each file inside said sub-directory. We then bind to that test file (which we will see in the next steps).
The folder structure inside the "test" directory is the same as in the "src" directory. With in each sub-directory there are files for testing that type of file (service, controller, etc...)
First, import chai. Also use the expect assertion style.
const chai = require("chai");
// Assertion style
const expect = chai.expect;
Inside a function "suite" write all your tests.
// **********TESTS**********
function suite() {
}
At last, make sure to export this "suite" function. As this is what we will bind in the main app.test.js file
module.exports = suite;
File naming: tests should always be named as following: [uniquename].test.js
.