<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Adeyinka Oresanya</title>
    <description>The latest articles on Forem by Adeyinka Oresanya (@ayk_dev).</description>
    <link>https://forem.com/ayk_dev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1005500%2F45607ea8-cf7a-469b-9341-53ce873cd224.jpg</url>
      <title>Forem: Adeyinka Oresanya</title>
      <link>https://forem.com/ayk_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ayk_dev"/>
    <language>en</language>
    <item>
      <title>Building a simple blog application with node.js</title>
      <dc:creator>Adeyinka Oresanya</dc:creator>
      <pubDate>Tue, 10 Jan 2023 18:05:26 +0000</pubDate>
      <link>https://forem.com/ayk_dev/building-a-simple-blog-application-with-nodejs-32g4</link>
      <guid>https://forem.com/ayk_dev/building-a-simple-blog-application-with-nodejs-32g4</guid>
      <description>&lt;p&gt;This is a walkthrough of I built a basic blog application using Express framework and MongoDB in nodejs. It is a simple CRUD application using the MVC pattern. This article is written with the assumption that the reader has an intermediate knowledge of JavaScript and nodejs, and so I will be skipping some granular details.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Software requirements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The first step in this project was to gather all the requirements needed for the functionality of the blog. The API should have endpoints where;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;New users can register.&lt;/li&gt;
&lt;li&gt;Existing users can log in.&lt;/li&gt;
&lt;li&gt;Only logged in users can create new blog posts.&lt;/li&gt;
&lt;li&gt;Both logged in and not logged in users can get all published blogs.&lt;/li&gt;
&lt;li&gt;Only logged in users can create new blog posts.&lt;/li&gt;
&lt;li&gt;Only logged in users can edit a post&lt;/li&gt;
&lt;li&gt;Only logged in users can edit a post.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;After gathering the requirements, it was time to set up my project. I used VS Code as my Integrated Development Environment(IDE).&lt;/p&gt;

&lt;p&gt;I created a .env file for environmental variables, which is added to git.ignore file to prevent accidental exposure of secrets&lt;br&gt;
I installed the necessary packages, set up my server to listen at a dedicated port and connected to the database. Read &lt;a href="https://medium.com/developers-compass/how-to-create-your-first-server-in-express-js-bd7bf1910925" rel="noopener noreferrer"&gt;this article &lt;/a&gt; on how to set up a server in Express. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fznt8ydtaulglu52dnv.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fznt8ydtaulglu52dnv.PNG" alt="Image description" width="637" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next I created a Data Access Object(DAO) or models for the user and the blog posts, based on the requirements. This is used to retrieve or send data to the database.&lt;/p&gt;
&lt;h5&gt;
  
  
  Blog Model
&lt;/h5&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require("mongoose");

const {readingTime } = require("../utils/readingTime")

const BlogSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true
  },

  description: {
    type: String,
    required: true

  },

  content: {
    type: String,
    required: true

  },

  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User'

  },

  state: {
    type: String,
    default: 'draft',
    enum: ['draft', 'published'],
    required: true
  },

  read_count: {
    type: Number,
    default: 0,
  },

  reading_time: {
  type: Number
},

  tags: [String],


  postedAt: {
    type: String,
    default: new Date().toString(),
  },
});


BlogSchema.pre('save', function (next) {
  let blog = this

  if (!blog.isModified('content')) return next()

  const timeTaken = readingTime(this.content)

  blog.reading_time = timeTaken
  next()
})

module.exports = mongoose.model("Blog", BlogSchema, "Blogs");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h5&gt;
  
  
  User Model
&lt;/h5&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
const validator = require('validator')

const Schema = mongoose.Schema;
const ObjectId = Schema.ObjectId;

const userSchema = new Schema({
  id: ObjectId,

  first_name: {
    type: String,
    required: true
  },

  last_name: {
    type: String,
    required: true
  },

  author_name: {
    type: String

  },

  username: {
    type: String,
    required: true

  },

  email: {
    type: String,
    required: true,
    unique: true
  },

  password: {
    type: String,
    required: true
    },

  blogs: [{type: Schema.Types.ObjectId, ref: "Blog"}]
});


userSchema.statics.signup = async function(first_name, last_name, username, email, password) {

  if (!first_name || !last_name || !username || !email || !password) {
    throw Error('All fields must be completed!')
  }

  const isinUse = await this.findOne({ email })

  if (isinUse) {
    throw Error('Email already exists')
  }

  const salt = await bcrypt.genSalt(10)
  const hashedPassword = await bcrypt.hash(password, salt)

  const author_name = first_name.concat(" ", last_name);

  const user = await this.create({ first_name, last_name, author_name, username, email, password: hashedPassword })

  return user
}

// static login method
userSchema.statics.login = async function(username, password) {

  if (!username || !password) {
    throw Error('All fields must be filled')
  }

  const user = await this.findOne({ username })
  if (!user) {
    throw Error('Incorrect username')
  }

  const matchPassword = await bcrypt.compare(password, user.password)
  if (!matchPassword) {
    throw Error('Incorrect password')
  }

  return user
}

module.exports = mongoose.model('User', userSchema)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, I created a service containing the methods needed for the endpoints for both users and blog posts. These will call the DAO methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const router = require("express").Router();
const Blog = require("../models/blogModel");


const getBlogs = async () =&amp;gt; {
    const blogs = await Blog.find().populate('author');
    return blogs;
  };

const getSpecificBlog = async (blogId) =&amp;gt; {
    const blog = await Blog.findById(blogId);
    return blog;
  };



const editBlog = async (blogId, title, description, content) =&amp;gt; {
    const editedBlog = Blog.updateOne({ _id: blogId }, { title, description, content })
    return editedBlog;
  };


const deleteBlog = async (blogId) =&amp;gt; {
    const deletedBlog = await Blog.findByIdAndRemove(blogId);
    return deletedBlog;
  };



module.exports = {
    getBlogs,
    getSpecificBlog,
    editBlog,
    deleteBlog
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next is to set up the controllers that will call the service methods. Controllers serve as the middlemen between route handlers and services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const blogService= require("../services/blog.service")

const getAllBlogs = async (req, res) =&amp;gt; {
    const blogs = await blogService.getBlogs();
    res.json({ data: blogs });
  };


const getSpecificBlog = async (req, res) =&amp;gt; {
    const { id } = req.params
    const blog = await blogService.getSpecificBlog(id);
    res.json({ data: blog });
  };


const editBlog = async (req, res) =&amp;gt; {
    const { id } = req.params;
    const { title, description, content } = req.body;
    const blog = await blogService.editBlog(id, title, description, content);
    res.json({ data: blog });
  };


const deleteBlog = async (req, res) =&amp;gt; {
    const { id } = req.params
    const deletedblog = await blogService.deleteBlog(id);
    res.json({ data: deletedblog });
  };



 module.exports= {
    getAllBlogs,
    getSpecificBlog,
    editBlog,
    deleteBlog
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I created the route handlers which will pass the request objects and related metadata to the controllers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const {getAllBlogs, 
    getSpecificBlog,
    editBlog, 
    deleteBlog}= require("../controllers/blog.controller");

const express = require('express');


const router = express.Router();


router.route("/")
    .get(getAllBlogs);


router.route("/:id")
    .get(getSpecificBlog)
    .put(editBlog)
    .delete(deleteBlog);


    module.exports= router
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I called the routes in the server.js file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express= require("express");
const db = require("./middleware/db");
blogRoutes= require("./routes/blog.routes")

require("dotenv").config()

PORT= process.env.PORT;

const app = express()

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


db.connectToMongoDB();

app.use('/blog', blogRoutes);

app.listen(PORT, () =&amp;gt; {
    console.log(`Server is listening at PORT ${PORT}`)
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the full project here on Github&lt;/p&gt;

</description>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
