5. Full Stack CRUD - NextJS app

Ayush RajputAyush Rajput
4 min read
  1. Create NextJS app

npx create-next-app@latest blog-app
cd blog-app
npm install mongoose joi
  1. Setup MongoDB and Connect

//src/database/index.js
import mongoose from "mongoose";
const dbConnect = async ()=>{
    const DB_URL = "mongodb+srv://********************.jxy98.mongodb.net/"
    mongoose.connect(DB_URL)
    .then(()=>console.log("DB CONNECTION SUCCESSFULL"))
    .catch((err)=>{
        console.log(err)
        console.log("Failed To Connect DB")
    })
}
export default dbConnect
  1. Create Model

//src/models/blog.js
import mongoose from "mongoose";
const blogSchema = new mongoose.Schema({
    title:{
        type:String,
        required:true
    },
    description:{
        type:String,
        required:true
    }
})
const Blog = mongoose.models.Blog || mongoose.model('Blog' , blogSchema)
export default Blog;
  1. Create APi Routes for Blog(POST)

//src/app/api/add-blog/route.js (this name must be same our route name will be add-blog
import dbConnect from "@/database"
import Blog from "@/models/blog"
import Joi from "joi"
import { NextResponse } from "next/server"

const AddNewBlog = Joi.object({   // for validation
    title: Joi.string().required(),
    description: Joi.string().required()
})
export async function POST(req){

    try{
        await dbConnect()
        const {title , description} = await req.json()  // like req.body
        const{error} = AddNewBlog.validate({
            title , description
        }) 

        if(error){
            return NextResponse.json({
                success:false,
                message: error.details[0].message  // suppose you pass number then it return title must be string
            }) 
        }
        const newBlog = await Blog.create({title , description})
        return NextResponse.json({
            success:true,
            message:"Blog added successfully",
            newBlog
        })
    }
    catch(err){
        console.log(err)
        return NextResponse.json({
            success:false,
            message:"Internal Server Error"
        })
    }
}
  1. API Call from frontend POST (formData)

  async function handleSaveBlogData(){  // onsubmit this will save our title and  description in DB

    if(!blogFormData.title || !blogFormData.description){
        toast.error("All fields are required")
        return
    }
    const toastid = toast.loading("Loading...")
        try{
            setLoading(true)
            const response = await fetch('/api/add-blog' , {
                method:"POST",
                body:JSON.stringify(blogFormData)
            })
            const result = await response.json()

            // console.log(result)
            if(result?.success){
                toast.success("Blog Added")
                setOpenDialouge(false)
                setLoading(false)
            }
        }
        catch(err){
            console.log(err)
            setLoading(false)
        }
        toast.remove(toastid)
        setBlogFormData({
            title:"",
            description:""
        })
    }
  1. Create API route for GET blog

//src/app/api/get-blog/route.js
import dbConnect from "@/database"
import { NextResponse } from "next/server"
import Blog from "@/models/blog";
export async function GET(){
    try{
        await dbConnect()
        const fetchBlog = await Blog.find({});
        return NextResponse.json({
            sucess:true,
            message:"Data fetched Successfully",
            data:fetchBlog
        })
    }
    catch(err){
        console.log(err)
        return NextResponse.json({
            sucess:false,
            message:"Internal Server Error"
        } , {status:500})
    }
}
// http://localhost:3000/api/get-blog this will be our url to check this api in postman
  1. API call from frontend to fetch data (GET)

// app/app/blogs/page.js
async function fetchBlog(){
    try{
        const response = await fetch('http://localhost:3000/api/get-blog' , {
            method:'GET',
            cache:'no-store'
        })
        const result = await response.json()
        // console.log(result)     
        return result?.data
    }
    catch(err){
        console.log(err)
    }
}
  1. Refresh the page on adding blog -

"use client"
import { useRouter } from "next/navigation"

function Blog (){
 const router = useRouter();
    const router = useRouter()
    useEffect(()=>{
        router.refresh();
    },[])
        if(result?.success){
             toast.success("Blog Added")
             setOpenDialouge(false)
             setLoading(false)
             router.refresh();
        }
}
  1. API Route to DELETE Blog

/src/app/api/delete-blog/route.js
import dbConnect from "@/database"
import Blog from "@/models/blog"
import { NextResponse } from "next/server"

export async function DELETE(req){
    try{
        await dbConnect()
        const {searchParams} = new URL(req.url);  // we do this other wise we have to make dynimic api roite for this
        const getCurrentBlogId = searchParams.get('id');

        if(!getCurrentBlogId){
            return NextResponse.json({
                sucess:false,
                message:"ID Not Found"
            });
        }
        await Blog.findByIdAndDelete(getCurrentBlogId)
        return NextResponse.json({
            success:true,
            message:"Blog Deleted"
        }, {status:200})
    }
    catch(err){
        console.log(err)
        return NextResponse.json({
            success:false,
            message:"Internal Server Error"
        }, {status:500})
    }
}
  1. Calling DELETE API from frontend

async function handleDeleteBlogByID(getCurrentID){
        const toastid = toast.loading("Loading...");
        try{
            const resposne = await fetch(`/api/delete-blog?id=${getCurrentID}` , {
                method:"DELETE"
            })
            const result = await resposne.json();

            if(result?.success){
                toast.success("Blog Deleted")
                router.refresh();
            }
        }
        catch(err){
            console.log(err)
        }
        toast.remove(toastid)
    }

// If < Doctype unexpected error came then see your mistake in url
  1. Update Blog (PUT) - API Route

import dbConnect from "@/database"
import Blog from "@/models/blog";
import Joi from "joi";
import { NextResponse } from "next/server"


const EditNewBlog = Joi.object({   // for validation
    title: Joi.string().required(),
    description: Joi.string().required()

})

export async function PUT(req){

    try{

        await dbConnect()
        const {searchParams} = new URL(req.url);
        const getCurrentBlogId = searchParams.get("id")
        const{title , description} = await req.json();
        if(!getCurrentBlogId){
            return NextResponse.json({
                sucess:false,
                message:"Blog ID Not Found"
            })
        }
        const{error} = EditNewBlog.validate({
            title , description
        }) 

        if(error){
            return NextResponse.json({
                success:false,
                message: error.details[0].message  // suppose you pass number then it return title must be string
            }) 
        }

        const updatedBlog = await Blog.findOneAndUpdate({_id:getCurrentBlogId} , {title , description} , {new:true})

        return NextResponse.json({
            success:true,
            message:"Blog Updated Sucessfully",
            updatedBlog
        })
    }
    catch(err){
        console.log(err)
        return NextResponse.json({
            sucess:false,
            message:"Internal Server Error"
        }, {status:500})
    }
}
  1. Frontend Call Update with - Add Blog

async function handleSaveBlogData(){

    if(!blogFormData.title || !blogFormData.description){
        toast.error("All fields are required")
        return
    }
    const toastid = toast.loading("Loading...")
        try{
            setLoading(true)
            const response = currentBlogId !==null ?  // currentblog id stored in state varibale after clickig edit blog button
            await fetch(`/api/update-blog?id=${currentBlogId}` , {
                method:"PUT",
                body:JSON.stringify(blogFormData)
            })
            :
            await fetch('/api/add-blog' , {
                method:"POST",
                body:JSON.stringify(blogFormData)
            })

            const result = await response.json()

            console.log(result)
            if(result?.success){
                toast.success("Blog Added")
                setOpenDialouge(false)
                setLoading(false)
                setCurrentBlogId(null)
                router.refresh();
            }
        }
        catch(err){
            console.log(err)
            setLoading(false)
        }
        toast.remove(toastid)
        setBlogFormData({
            title:"",
            description:""
        })
    }
0
Subscribe to my newsletter

Read articles from Ayush Rajput directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ayush Rajput
Ayush Rajput