Start by installing NodeJS and npm. There's a straight forward tutorial on how to do that on the NodeJS website.
Requires Node v10 or later
We use MongoDB
to store data.
Download it from their website.
Once you've installed it, make sure that it's running before you try to run the website. If it's not running, an error message will be printed.
Clone the repository by running
git clone https://github.com/SimonKinds/4temps-tournament.git
The directory 4temps-tournament will henceforth be called the root directory.
Some parts of the application is configured via environment variables.
These can be set in a .env
file in the root directory.
An example .env
file can be seen below.
Setting these are required. The example below will give you a fully functioning example.
NODE_ENV=development
DB_URI=mongodb://localhost/4temps
COOKIE_SECRET="super secret cookie secret"
HOSTNAME=localhost
PORT=3000
Go to the root directory of the project.
Once there, run npm install
to install all the dependencies of the project.
This may take a while.
You're now all set to run the website!
From the root directory of the project run npm start
and wait for quite some time.
The reason it takes a while is that babel
compiles the server code, and webpack
bundles all the frontend code into a single file.
Once the bundle is created, the server will restart.
And here I thought javascript wasn't a compiled language...
You should now be able to visit http://localhost:3000
.
Any changes to the source files will automatically recompile the project and restart the server.
Running npm start
will create a non-optimized version, used for development.
To create a optimized version, run the following commands.
Make sure that npm start
is not running.
npm run build
npm run start:prod
Once again, you should be able to visit http://localhost:3000
.
User input has to always be validated before handled on the server. To enable a more responsive user experience, it's recommended to also validate on the client, before forwarding the request to the server.
The validators should be shared between the front-end and back-end, and be placed in src/validators
.
It's recommended to create a type representing a summary of the errors, to enable better error messages for the user (and the developer).
An example can be found in src/validators/validate-user.js
type UserCreateValidationSummary = {
isValid: boolean,
isValidEmail: boolean,
isEmailNotUsed: boolean,
isValidFirstName: boolean,
isValidLastName: boolean,
isValidPassword: boolean,
};
In the above example there is one field that can not be checked by the client, isEmailNotUsed
.
Therefore, validate-user
will set isEmailNotUsed
to true
if access to the database is not given.
Anything that accesses the database should be abstracted away from the code that uses the result.
Any database access should be placed in a file with the same name as the table it accesses in the src/data
directory.
For example, access to user
table (or collection using MongoDB vocabulary) is placed in src/data/user.js
and exports a UserModel
that represents the database user type.
What follows is a short example of how access to a user might be implemented.
// @flow
import mongoose from 'mongoose';
export type UserModel = {
_id: ObjectId,
email: string,
password: string
}
const schema = new mongoose.Schema({
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
});
const Model = mongoose.model('user', schema);
export const getUserFromId = async (userId: ObjectId): Promise<?UserModel> => {
try {
return await Model.findOne({ _id: userId });
} catch (e) {
return null;
}
};
jest is used for testing.
To run the tests, simply execute npm test
.
Tests should be placed in a __tests__
folder, in whatever directory the file you're testing is in, e.g. the test for src/validators/validate-user.js
should be placed in src/validators/__tests__/validate-user.js
How to write tests can be found on jest's website, but here's a short example taken from their documentation.
test('two plus two is four', () => {
expect(2 + 2).toBe(4);
});
and an example from our codebase using async
and await
.
test('Valid info is valid', async () => {
const user: UserCredentials = {
email: 'test@test.com',
password: 'password'
};
const result = await validateUserLogin(user);
expect(result.isValid).toBe(true);
expect(result.isValidEmail).toBe(true);
expect(result.isValidPassword).toBe(true);
expect(result.doesUserExist).toBe(true);
});