- Express is mostly popular because of 3 main things, the routes, middleware, and request-response
- Express have some import middleware body-parser: To parse http request body compression: To compress http responses cookie-parser: parse cookie header and populate req.cookies multer: handle multipart form data serve-faviconz; serve a favicon session: establish server-based sessions (development only) helmet: for securing an app passport: for authentication using strategies such as OAuth, OpenID, and many others
- We use app.engine to pass templates to the app
- When using databases, it is good to have a test, production, and development database
- Installation
npm install --save mongoose
- Connecting with the MongoDB client:
const mongoose = require("mongoose");
module.exports.connectDatabase = async (dbUrl) =>
mongoose.connect(dbUrl, { useNewUrlParser: true });
// to run the code
const { connectDatabase } = require("./db");
connnectDatabase.connect(dbUrl).then().catch();
- Data Schema in Mongoose: Mongoose allows the database developers to create schemas for their databases. This can be done using the mongoose schema method from mongoose. When using emails in the schema, we can use the email validator module to check if our email is valid or not.
const mongoose = require("mongoose");
const userSchema = mongoose.Schema(
{
name: {
type: String,
minLength: 3,
require: true,
index: { unique: true },
trim: true,
},
},
{ timeStamp: true }
);
module.exports = mongoose.model("User", userSchema);
Using bcrypt to Hash and Compare Passwords: It is bad practice to store password in plaintext. So we use a tool to store the password as a hash. We use a tool called bcrypt for this. Bycrypt hash has the structure: version | Rounds | Salt | Hash
. To find out if the a password is correct, bcrypt gives a function that compares the hash of the entered password to the stored hash.
console.log("hello world");
- Installing bcrypt:
npm install --save bcrypt
- Initialising bcrypt: import bcrypt with the require function, then pass the salt rounds. Then we have to write 2 pieces of code for the hashing of the password and the comparing of the password.
const bcrypt = require("bcrypt");
// getting the hash
userSchema.pre("save", async function preSave(next) {
const user = this;
if (!user.isModified("passworcleard")) return next();
try {
const hash = await bcrypt.hash(user.password, SALT_ROUNDS);
user.password = hash;
return next();
} catch (error) {
return next(err);
}
});
// compare function
userSchema.methods.comparePassword = async function comparePassword(candidate) {
return bcrypt.compare(candidate, this.password);
};
module.exports = mongoose.model("User", userSchema);
-
For authenticating users, one of the tools we can use is bcrypt since it provides a method to hash the password then compare the user password with the previous password. We also used the email-validator module to check if the email was valid.
-
Cookies and Sessions: Cookies and sessions are one of the building blocks for making authentication secured on the app, server, and database.
-
We can set certain parameters for cookie:
id, expiry date, security (if we want to allow the client to read the cookie)
. -
To use cookie we need the
cookie-parser
. It is a 3rd party package, but it is available in express. When put on the right position, it allows the server to read the cookie header from the routes usingreq.cookie
const cookieParser = require("cookie-parser");
const express = require("express");
const app = express();
app.use(cookieParser()); // req.cookie ==> to get the cookie header
- Express session is used to manage express session data.
express-session
gives the ability to store the data on the backend. Express session usesconnect-mongo
to connect with a mongodb database.
modules needed
- express
- cookie-parser
- express-session
- connect-mongo
- Passport is the most used package for nodejs. It provides an authentication function that uses strategies to authenticate the user. To install passport
npm install --save passport
- passport does not only makes the authentication process easy, but it also handles storing the login info in the cookies and it does not have to be done manually by the programmer.
- Passport provides 2 functions that make the authentication process easy
const passport = require("passport");
passport.initialise();
passport.session();
- When dealing with authentication from a local database, we need a tool to interact passport with that database, for this we use
npm install --save passport-local
. - After installing this tool, we have to use we have to setup a local strategy to use the passport elements in the passport middleware. In this middleware, we then write and async function that can authenticate the user with the database.
- The next step is to write a serialization and deserialization the user data with passport.
const passport = require("passport");
passport.serializeUser((user, done) => {
return done(null, user._id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await accountsCollection.findOne({ _id: id });
return done(null, user);
} catch (error) {
return done(error);
}
});
- Mongoose and passport maintains a global state thereby distributing their models, variables, functions when the moduled is imported anywhere in the project.
-
First import all the resources need: mongodb client, express, express session, cookie-parser, connect-mongo
-
Set the client and dbName variables
-
Set the middleware with app.use and pass all the middlewares
const { MongoClient } = require("mongodb");
const client = new MongoClient(dbUrl);
const session = require("express-session");
const cookieParser = require("cookie-parser");
const MongoStore = require("mongo-connect");
const express = require("express");
const app = express();
app.use([
express.json(),
express.urlencoded(
{ extended: true },
session({
secret: "my secret key",
resave: false,
saveUninitialized: true,
store: MongoStore.create({ client: client, dbName: dbName }),
cookie: { secure: false },
})
),
]);
- To work with passport we need the following packages
- mongodb
- express
- express-session
- cookie-parser and body-parser
- passport-local
- mongo-connect
- First, on the form attribute
enctype
and set it tomultipart/form-data
<form actions="" method="post" enctype="multipart/form-data"></form>
- To hanlde these files in the form in express, we have to use a middle and we can use that from an npm package
multer
.
npm install multer
- multer allows the configuration of file size, for example
const multer = require("multer");
const upload = multer({
limits: {
fileSize: 4 * 1024 * 1024,
},
});
module.exports = multer;
- We can now import this middleware in the file to be used and pass it to the route.
const multer = require("../middlewares");
const express = require("express");
const app = express();
app.post('/registration',multer.single(<fieldname>) ,(req, res)=>{
res.end()
})
- When dealing with files like images, we must also handle the file extension carefully to make sure that it fits the app backend.
- We can use the
sharp
module when dealing with images. This allows us to resize the image and convert the image to png since it is the best to work with on the internet.
- Environment variables have a great effect on the node memory. So we must differentiate them for production and development
- Nodejs is single threaded and synchronous so it is best practiceto use asynchronous methods when building a nodejs application
- When a nodejs application is in production, the application runs differently and uses more memory. We must add a package to the root of the project to compress the size of the package. The name of the package is
compression
. To install, just runnpm install compression
and for usage, just pass to the expressapp.use()
as a middleware
const compress = require('compression');
const express = require('express');
const app = express()
# adding to app.use()
app.use(compress())
-
We must always handle all errors and exceptions in a node application or else this can cause the application to crash when in production.
-
In production, it is bad to use
console.log()
since it is synchronous. We will use another packagebunyan
. To install,npm install --save bunyan
. With bunyan, we can separate the different loggers for development, test, and production. -
We can use the nodejs in built module
cluster
to help improve our nodejs application during production. We can combine this cluster module with the node os module to put the CPUs in more organised work. -
Before deploying an application, it must some security measures. Express has some security checks that can be used but we can use NGINX for that purpose. We must make sure that all the dependencies are secured; to do this, run
npm audit
-
To add security to express, we can use the helmet. It provides some middleware to prevent possible attacks on an application. We can use install helmet with npm
npm install helmet
. Then we can add it in expressapp.use(helmet())
as middleware. -
We can deploy our application to a server using PM2. This is good for small projects. First we have to install pm2 globally
npm install -g pm2
. PM2 requires a configuration file for the deployment calledecosystem.config.js
. -
After setting the config file we have to run the follow commands
pm2 deploy production
pm2 deploy production
- We can run
pm2 status
to check the status of the pm2 application. We can also runpm2 save
to reserve the setup. Then we runpm2 startup
- We can use NGINX to do reverse proxies and install all SSL/TLS certificates. When we setup the NGINX, we have to reset the express session so it run in production. we have to make the set parameters like: secret, name, proxy, then make the cookie security
true
.