My first blog with MERN Stack (Back-end)
Tags: node, javascript, webdev, mongodb
Published: 2020-05-04 19:20:50

# All about my blog: Back-end

# Back-end blog: How?

In this article, I am going to explain how I created the backend for my blog,
what technogies I used and why, this is not a step-by-step guide, it is only a resource if you don't know how to start making your own blog, maybe this can help you on the technologies you need to learn. We have a lot of information on the internet and sometimes it is a little difficult to find a correct answer to our problems.

All the code of my backend is [here](https://github.com/rhodlib/mern_personal_blog/tree/master/server)

---

---

## Index

- **Dependencies**
  - ExpressJS
  - Mongoose
  - dotenv
  - cors
  - validator
  - bcryptjs
  - jsonwebtoken
  - slugify
- **Database**
  - MongoDB
- **Structure**
  - Controllers
  - db
  - middlewares
  - models
  - routes

---

---

## **Dependencies**

In a few words, I will try to explain these dependencies and why I use them.

---

### ExpressJS

The language we use to make this blog is **JavaScript**, for that reason i use **NodeJS** for the backend, **NodeJS** allows us to run **JavaScript** on the server side.

**ExpressJS** is nothing more than a web _framework_ for **NodeJS**, it is robust and has a lot of features to make our lives easier when using **NodeJS**, for example it allows us to configure a server in 6 lines of code or less.

```javascript
const express = require("express"); // 1
const app = express(); // 2

app.listen(3000, function () {
  // 3
  console.log("Server listening on port 3000"); // 4
}); //5
```

1. **Why ExpressJS?** Because is the most popular framework for **NodeJS**, And when it comes to getting a job, it is the most demanded.

2. **Are there other frameworks for NodeJS?** Sure! we have other awesomes frameworks for **NodeJS**.
   - [Hapi](https://hapi.dev/)
   - [Sails](https://sailsjs.com/)
   - [Koa](https://koajs.com/)
   - [Socket](https://socket.io/)
   - [NestJS](https://nestjs.com/)
   - and much more
3. **How can install express on my server folder?** if you has the **package.json** file on your folder, only need to run the following command
   `$ npm install --save express`
4. **It's hard to use?** No, you really have all the information you need in the official [Docs](https://expressjs.com/)

---

### Mongoose and MongoDB

As the official website says, **mongoose** is a elegant **mongodb** object modeling for **NodeJS**, what does that mean?.

Well, **MongoDB** is a system of databases **NoSQL**(Not Only SQL),
is a document-based database, we can store information in
**JSON** (JavaScript Object Notation) format within documents and these documents are saved in collections with an ID provided by **MongoDB**.

But the only way we have to keep organized the data entering and leaving the database is **mongoose**. Has functions to create a Schema and models.

**What is a Schema?** Schema is an **Object** that allows us to declare certain values ​​and generate validations before sending the data to the database. thus allowing us to manage the same structure in all the data that we store.

this is the schema of an article of my blog , this is how the article is store to the database

```javascript
const { Schema, model } = require("mongoose");

const postSchema = new Schema(
  {
    image: String,
    title: {
      type: String,
      required: true,
    },
    description: String,
    markdown: {
      type: String,
      required: true,
    },
    createdAt: {
      type: Date,
      default: Date.now,
    },
    slug: {
      type: String,
      required: true,
      unique: true,
    },
  },
  {
    timestamps: true,
  }
);

const Post = model("Post", postSchema);

module.exports = Post;
```

with this schema we create the model that we are going to use to store, save, delete and read the articles in the database.

**Mongoose** also allows us to connect to the database in a very easy way.

```javascript
const mongoose = require("mongoose");

const URI = "mongodb://localhost/dbtest";

mongoose.connect(URI);

const connection = mongoose.connection;

connection.once("open", () => console.log("DB is connected"));
```

**Where can get more info about mongoose?** mongoose has simple and easy-to-read [docs](https://mongoosejs.com/docs/guide.html)

---

### dotenv

dotenv is an npm package that allows us to create environment variables. An environment variable is a dynamic variable, it's as simple as writing a variable to an .env file and using it as a reference.
**why do this?** because we can protect sensitive information or data in the variable (database urls, passwords, tokens) when we upload the files to repositories or servers.

**How can install dotenv in my project?** `$ npm install --save dotenv`

**How to configure dotenv to work with de project?** only need to add a line of code in the top of the index.js.

```javascript
require("dotenv").config();
```

and then, you can create a .env file in the root of your project. more info about dotnev [here](https://www.npmjs.com/package/dotenv)

---

### Cors

Cors is simple, I use it because allows me to have two servers at the same time on a different port and to be able to communicate between them, the backend server with nodemon and the frontend server with npm start

**How can install cors?** `$ npm install --save cors`

**How usage cors?** in the index.js of server or wherever you have your app

```javascript
const express = require("express");
const cors = require("cors");
const app = express();

app.use(cors());
```

more info about cors [here](https://www.npmjs.com/package/cors)

---

### Validator

validator is a library of string validators and sanitizers

I use this on the User model, to validate the email property inside the userSchema

```javascript
const validator = require("validator");

email: {
      type: String,
      required: true,
      unique: true,
      trim: true,
      lowercase: true,
      validate(value) {
        if (!validator.isEmail(value)) {
          throw new Error("Email is invalid");
        }
      },
    },
```

you can see the full code [here](https://github.com/rhodlib/mern_personal_blog/blob/master/server/src/models/User.js)

**How can install validator?** `$ npm install --save validator`

**Where can learn more about validator?** you read more [here](https://www.npmjs.com/package/validator)

---

### bcryptjs

bcryptjs is an npm package to encrypt, I use this for encrypt passwords, is very easy to use and secure with more than 700k+ downloads per week.

**How install bcryptjs?** `$ npm install --save bcryptjs`

**How i use bcryptjs?**

I use bcrypt in two functions of the "User model", one is creating a method for the user model through the userSchema to encript password.

User.js - [Here](https://github.com/rhodlib/mern_personal_blog/blob/master/server/src/models/User.js) is all the code

```javascript
const bcrypt = require("bcryptjs");

//Here i created a method for userSchema called encryptPassword
userSchema.methods.encryptPassword = async (password) => {
  // get the password
  return await bcrypt.hash(password, 8); // 8 is a cicle this been hashed 8 times
  // and then return the password hashed by a function of bcrypt
};
```

And later we need a function to desencrypt the password to validate password and for this I create a static method. static method is a function accesible in the model and not in the userObject

```javascript
//Here i created a static method to find credentials and validate password
userSchema.statics.findByCredentials = async (email, password) => {
  //Get email and password
  const user = await User.findOne({ email }); //Search by email using the model (findOne is a static method)
  if (user) {
    // If user exist
    const isMatch = await bcrypt.compare(password, user.password);
    // use a function called compare from bcrypt and compare the password with the user.password in the database.
  }
};
```

---

### Slugify

Slugify is an npm package to create a slug from a string.

**What the f\*ck is an slug?** slug is than simple like this "hello-how-are-you", it's a string with dash instead of spaces.

**Why i need slug?** In this blog I use slug like a unique property of each article, using his title as slug, why? because I can search and article for slug and not necesary by ID.

**This is te best solution?** Not, because the best practice is use an ID, but is right for me.

**How slug help you?** It's simple, finding by id, the route in the front-end it's something like this `blog.rhodlib.me/article/5468fds1684541sdf18546516s8` this is not estetic, isn't nice to see.
but if find by slug, the route is something like this `blog.rhodlib.me/article/all-about-my-blog-backend-how`

**How can install slugify?** `$ npm install --save slugify`

**How use slugify?** Is very easy, let's see.

Post.js [here](https://github.com/rhodlib/mern_personal_blog/blob/master/server/src/models/Post.js) is all the code.

```javascript
const slugify = require("slugify");

//the function pre of the postSchema allows us run a function between the validate and the store article on the database
postSchema.pre("validate", function (next) {
  const post = this;

  if (post.title) {
    post.slug = slugify(post.title, { lower: true, strict: true }); // We use slugify to create the slug with the title, before save the article in the database
  }

  next();
});
```

**Where can get more info about slugify?** you can go [here](https://www.npmjs.com/package/slugify)

---

### jsonwebtoken

jsonwebtoken is library to create validation tokens, I use this to validate user when they are connected in the app.

**How use JWT in the blog?** I use jwt in the following way.

User.js - [here](https://github.com/rhodlib/mern_personal_blog/blob/master/server/src/models/User.js) is de full code

```javascript
const jwt = require("jsonwebtoken");

// here i created a method for each User called generateAuthToken
userSchema.methods.generateAuthToken = async function () {
  const user = this;

  const token = jwt.sign(
    // With jwt.sing() we create a token
    { _id: user._id.toString() }, // I pass the user id in an object
    process.env.AUTHTOKENSTRING // I use an environment variable to encrypt the token with a secret word
  );
  user.tokens = user.tokens.concat({ token }); // And then I put the new token in the user's token array
};
```

---

---

## **Structure**

I will explain the structure that I use in the project.

In the server folder I create a src folder in the first level, inside of this folder I create five folder more called:

- controllers
- db
- middlewares
- models
- routes

and two files **app.js** and **index.js**

---

### Controllers

[here](https://github.com/rhodlib/mern_personal_blog/tree/master/server/src/controllers) I create the controllers of the routes, when a request enters the server, the path executes a function, that function is stored in the controllers.

auth.controller.js - [here](https://github.com/rhodlib/mern_personal_blog/blob/master/server/src/controllers/auth.controller.js) is the full code

```javascript
const authCtrl = {};

authCtrl.registerUser = async (req, res) => {
  // Code
};

authCtrl.loginUser = async (req, res) => {
  // Code
};

module.exports = authCtrl;
```

---

### DB

[here](https://github.com/rhodlib/mern_personal_blog/tree/master/server/src/db) I create a file called **mongoose.js** and store my access to database with mongoose.

---

### Middlewares

[here](https://github.com/rhodlib/mern_personal_blog/tree/master/server/src/middlewares) I create my middlewares, only have one. **auth.js** where realize the authorization for the login.

---

### Models

[here](https://github.com/rhodlib/mern_personal_blog/tree/master/server/src/models) I create my two models, with their own schemas.

---

### Routes

[here](https://github.com/rhodlib/mern_personal_blog/tree/master/server/src/routes) I create the routes for the request. I have three files, within each one the routes are detailed:

- auth.routes.js
- post.routes.js
- user.routes.js

auth.routes.js - [here](https://github.com/rhodlib/mern_personal_blog/blob/master/server/src/routes/auth.routes.js) is the full code

```javascript
const { loginUser } = require("../controllers/auth.controller");

router.post("/api/user/login", loginUser);

module.exports = router;
```

---

---

## THE END

And this is all the backend of my blog, I hope you find it interesting and guide you in case you do not know how to start