5. Full Stack CRUD - NextJS app

4 min read
Create NextJS app
npx create-next-app@latest blog-app
cd blog-app
npm install mongoose joi
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
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;
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"
})
}
}
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:""
})
}
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
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)
}
}
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();
}
}
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})
}
}
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
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})
}
}
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
