Skip to content

Earth-Hominid/Vivacity-Blog-Creator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vivacity | Full Stack MERN App

MongoDB Express.js NodeJS React Redux

A free platform to create and host your own blog.

Click here for the live demo. (The application will take a few seconds to start from sleep.)

Screen Shot 2022-06-22 at 11 37 32 AM

Description

Blog Creator was written using the Model-View-Controller architecture and the RESTful API framework. The application allows a user to create an account with email. Once they are logged in, and authenticated, they can create and save blog entries.

Screen Shot 2022-06-21 at 12 36 08 PM

Backend

The server is written with Express. User details and blog entries are saved in a MongoDB database. Mongoose is utilized as the ORM.

The backend was built using the ExpressJS framework along with the Model-View-Controller (MVC) architecture pattern. This architecture separates the data management (the "model"), user interface (the "view"), and control flow (the "controller").

MVC was chosen because it offers code which is easier to understand and maintain, along with the added benefit of ease of ability in testing and extending the functionality of the application, if needed. Furthermore, it organises the routes and handlers in a logical and maintainable format.

MongoDB (a NoSQL database) was chosen because it can handle large numbers of read and write operations in parallel, which makes it well-suited for use cases with high write loads such as a content management system.

Another benefit MongoDB provides over a SQL database, is it's design, which allows it to handle large amounts of unstructured data, making it more flexible and scalable.

Backend Security

Authentication provided by confirming user is in the database, while authorization is confirmed using JSON Web tokens to protect backend routes.

User passwords are first hashed using bcryptjs and then saved in the database as a hashed password.

Authentication is implemented by using JSON Web Token authentication. JWT's are signed using a secret along with the HMAC algorithm. Blog entries are attached to their account specifically using JSON Web token and stored in MongoDB.

User passwords are encrypted and stored in MongoDB using the BcryptJS package. Bcrypt is password hashing algorithm which protects against Rainbow attacks by utilizing a salt and against brute force attacks.

Screen Shot 2022-06-21 at 12 34 02 PM

Frontend

Redux and Redux toolkit are utilized for state-management. The majority of CSS was created using the TailwindCSS library along with Styled-Components. The website is suitable for both smartphones and large monitors. The UI was designed for mobile use first.

Screen Shot 2022-06-21 at 12 36 55 PM

Lessons learned

Middleware

Using Express's built in middleware function 'urlencoded' allows incoming requests with urlencoded payloads to be parsed. The parsed data is populated on the request object (req.body) and it contains key-value pairs which can either be a string or an array when 'extended' is set to false.

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

Error Handling Middleware

I was able to overwrite the Express error handler with my own middleware function. When set to 'development' it will return the error message and the stack, when server is set to 'production', only the message is returned.

const errorHandler = (error, req, res, next) => {
  const statusCode = res.statusCode ? res.statusCode : 500;

  res.status(statusCode);

  res.json({
    message: error.message,
    stack: process.env.NODE_ENV === 'production' ? null : error.stack,
  });
};

module.exports = { errorHandler };

Async/Await with Mongoose Promise

When interacting with our database using Mongoose, we will be recieving back a 'Promise', thus we need to use 'async/await'.

The Express-Async-Handler package is quite useful as we can use async/await without the extra boilerplate of 'try/catch'. We simply bring in the package and wrap the function with the handler:

const asyncHandler = require('express-async-handler');

const getBlogs = asyncHandler(async (req, res) => {
  res.status(200).json({ message: 'Get blogs' });
});

Authentication Route Protection Middleware

Utilizing JSON Webtokens, we can write a function that that protects our routes by checking that our headers have the authorization object and they start with 'Bearer' and the token.

const protectRoute = asyncHandler(async (req, res, next) => {
  let token;

  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith('Bearer')
  ) {
    try {
      // Get token from header
      token = req.headers.authorization.split(' ')[1];

      // Verify token
      const verifyTheToken = jwt.verify(token, process.env.JWT_SECRET);

      // Get user from the token
      req.user = await User.findById(verifyTheToken.id).select('-password');

      next();
    } catch (error) {
      console.log(error);
      res.status(401);
      throw new Error('Not authorized');
    }
  }
  if (!token) {
    res.status(401);
    throw new Error('Not authorized, no token');
  }
});

Redux & Redux Toolkit

Slice files contain logic, while the service files contain HTTP requests, sending data, and setting data in local storage. Axios is used for HTTP requests from the client-side (frontend).

In order to obtain the 'user' from local storage (if they have previously logged in) with the JSON Webtoken, we need to use JSON.parse as local storage only stores strings:

const user = JSON.parse(localStorage.getItem('user'));

Dependencies

Server-Side / Backend

Client-Side / Frontend