Blog API with Nodejs,Expressjs and Mongodb
Collins Mbathi
Posted on October 11, 2021
Introduction
This is a simple API for a blog. It includes authentication so that only the owner of the blog can create, edit, and delete posts. It uses Node, Express, and MongoDB.
The API has the following endpoints:
Method | Endpoint | Description |
---|---|---|
POST | /api/posts | Creates a new post. Requires authentication. |
GET | /api/posts | Gets all posts. |
GET | /api/posts/:id | Gets a single post by id. |
PUT | /api/posts/:id | Updates a post. Requires authentication. |
DELETE | /api/posts/:id | Deletes a post. Requires authentication. |
POST | /api/register | Registers a new user. |
POST | /api/login | Logs in a user. |
POST | /api/logout | Logs out a user. Requires authentication. |
In the following section, we will look at some of the prerequisites for this tutorial.
Prerequisites
The following are required to complete this tutorial:
Nodejs installed on your system.
Expressjs installed on your system.
Sound knowledge of JavaScript and Nodejs.
-MongoDB make a connection with MongoDB database .
Setup
Let's get started with the Node.js code. Make a folder called Blog site API.
Then, in the terminal, type npm init -y
to create a package.json file.
After that, you must install some packages before proceeding.
These packages will be used throughout the project.
Install Express,Mongoose,dotenv,bcryptjs in the api folder using the terminal.
npm i express mongoose dotenv bcryptjs
When the packages are installed, make a file called .env. After that, launch MongoDB and copy the link to our project.
mongodb+srv://user:password@cluster0.hex8l.mongodb.net/name-database?retryWrites=true&w=majority
The MongoDB address We'll use the dotenv package to connect it to the main folder. The package assists us in separating secrets from source code. This is helpful when uploading your project to GitHub. where you may not want to share your database login information with others You instead distribute the source code. As you can see, I need to keep my password hidden in the project.
I've also installed bcryptjs
as seen above. This package enables us to create a password security platform that scales with computation power and always salts every password.
Let's make our main file and call it index.js. This is where all routes and middleware will be assembled. Before proceeding, import nodemon into the API folder. Any changes to the code in the index.js file cause the Node server to restart instantly.
npm i nodemon
Initial Route Setup
Let's start with the first route, which checks to see if everything is in order. The Node.js Express package allows you to create routes, which is how the majority of the Internet works. Most back-end languages, such as Node.js and Java, provide the ability to create these routes that interact with databases. The first route does not interact with the database and simply returns a text when accessed via a GET request.
In the API folder, create an index.js file. First, import the Express and Mongoose packages. Next, use Express to create a port variable that will run on the port you will be given, or port 5000 if no ports are available.
const express = require('express');
const mongoose = require('mongoose');
//App Config
const app = express()
const port = process.env.PORT || 5000
//Middleware
//DB Config
//API Endpoints
//Listener
app.listen(port, () => console.log(`Listening on localhost: ${port}`))
Access to the Database and the Network
You must create a database user in MongoDB and grant network access. and use dotenv to connect it to the initial routes because we've saved our link in the.env file .
const dotenv = require("dotenv");
dotenv.config();
//Database Connection
Connect.CONNECTDB(process.env.URL);
Database Schema and Routes
MongoDB, the database we're using, stores data in JSON format rather than the regular table structure found in traditional databases like Oracle. You create the schema file that MongoDB requires. It describes how fields in MongoDB are stored.
First, make a folder called models. Create a file inside the folder and name it 'User.js.' This is where we will write our authentication schema.
Auth Schema
We will begin by developing the authentication schema for users who register on the site. The user information is saved in the database. As a result, when the user returns later, they will simply log in because the server will recognize them based on the information saved.
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username:{
type: String,
required: true,
unique:true,
min:3,
max:20
},
email:{
type: String,
required: true,
unique:true
},
password:{
type: String,
required: true,
min:3,
max:10
},
},
{timestamps: true}
);
module.exports = mongoose.model("User", UserSchema);
In addition, as seen in the code above, in the last line, we exported our code in order to import it into the routes.
As you can see, the schema contains details such as username, email, and password that will be stored in the database. When a user attempts to log in, the server will check to see if the user exists in the database and will allow the user if the user details are in the database.
Let us now create the Post Schema in which we will store what we want to be in our post.
In the models folder, the folder creates a file called 'Post.js,' which is where we will write our Post Schema.
const mongoose = require('mongoose');
const PostSchema = new mongoose.Schema({
desc: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
{timestamps: true}
);
module.exports = mongoose.model('Post', PostSchema);
Our post schema includes the title and description that will be stored in the database.
The schema is now used to create the endpoint that adds data to the database. The MVC pattern is used here; this is the standard flow of a web application.
Then, use a POST request to send any data from the user to the database. Any endpoint can be used. If you write an article on Dev.to and then hit the POST button, your article is saved in the Dev.to database once the POST request is made.
The GET endpoints retrieve all database data. Again, any endpoint can be specified. When you browse through the posts in Dev.to, for example, a GET request is sent to the endpoint, which retrieves all posts from the Dev.to database.
routes
Create a folder called routes. We'll start with the Authentication route first. Create a file in the routes folder called Auth.js with the following authentication codes: -
const router = require('express').Router();
const User = require('../models/User');
const bcrypt = require('bcryptjs')
//register endpoint
router.post('/register', async (req,res)=> {
// const confirm = await User.find({Username : req.body.username ,email : req.body.email})
//confirm && res.status(400).json('this user or email exist');
try {
const salt = await bcrypt.genSalt(10);
const hashedPass = await bcrypt.hash(req.body.password, salt);
const savedPost = await new User({
username: req.body.username,
email: req.body.email,
password: hashedPass
})
const resultPost = await savedPost.save();
res.status(200).json(resultPost);
} catch (error) {
res.status(500).json(error);
}
})
//login endpoint
router.post('/login', async (req,res)=>{
try {
const user = await User.findOne({username : req.body.username});
!user && res.status(400).json('wrong user');
const validate = await bcrypt.compare(req.body.password,user.password);
!validate && res.status(400).json('wrong password');
const {password, ...others} = user._doc;
res.status(200).json(others);
} catch (error) {
res.status(500).json(error);
}
})
module.exports = router;
As you can see in the code above, we imported the schema and will use it to insert and save the details.
POST a request to the /register endpoint. To MongoDB, the load is in req.body.username,password,email. Then you send the User information using the New
method. If it is successful, you will be given status 200; otherwise, you will be given status 500.
To get the data from the database, create a post endpoint to /login.
You're using findOne() here and getting a success code of 200. (otherwise, status 500).
As previously mentioned, we used bcryptjs in the code to protect our passwords.
Let's go to the Post routes, shall we? Make a file called 'Post.js' in the routes folder. The Post file's codes are listed below.
const router = require('express').Router();
const Post = require('../models/Post');
//create post
router.post('/', async (req,res)=> {
try {
const savePost = await new Post(req.body);
const savedPost = await savePost.save()
res.status(200).json(savedPost);
} catch (error) {
res.status(500).json(error);
}
})
//update post
router.put('/:id', async (req,res)=> {
try {
const post = await Post.findById(req.params.id);
if(post.userId === req.body.userId) {
await Post.updateOne({$set:req.body});
res.status(200).json('it has been updated);
} else {
res.status(403).json('you can only update your post');
}
} catch (error) {
res.status(500).json(error)
}
})
//delete post
router.delete('/:id', async (req, res)=> {
try {
const post = await Post.findById(req.params.id);
if (post.userId === req.body.userId) {
await Post.delete()
res.status(200).json('the post is deleted)
} else {
res.status(403).json("you can only delete your post")
}
} catch (error) {
res.status(500).json(error)
}
})
//get All posts
router.get('/', async (req,res) => {
try {
const posts = await Post.find();
res.status(200).json(posts);
} catch (error) {
res.status(500).json(error);
}
})
//get one post
router.get('/:id',async(req,res)=> {
try {
const post = await Post.findById(req.params.id);
res.status(200).json(post);
} catch (error) {
res.status(500).json(error);
}
})
module.exports = router;
In our code above, we created our post, saved it, were able to edit it, delete it, and could retrieve all of the posts or just one.
First, we create the post using the post
method and save it as directed. We used the put
method to edit the post, and after finding it using the findById
method provided by the mongoose package, we used the update
method to update the post.
in the third method, we use the delete
. where we find the post we want to delete using the findById
method and use the delete() to delete the post.
Also, in the last line of our code, we have exported our code using a router and used the first get to find only one post and the second get to find all the posts. This enables us to easily track our handle request and send it to the main file index. Let me demonstrate in the screenshot below.
As shown in the above screenshot, we can now access our routes as middleware by using the use()
function. When we import our codes, the router function makes it easier.
example import authroute = require('./routes/Auth');
Finally, as shown, we create the endpoint /api/blog
and the router.
Let's not forget about the express. json() middleware is a method built into express that recognizes the incoming Request Object as a JSON Object because our data is in JSON.
Thank you for reading the article. I hope you learned a lot from it. In the next article, we will learn how to test it in Postman Software.
Posted on October 11, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.