Back to all posts

Building a REST API Comment Section for Your Portfolio with Next.js and MongoDB

2023-07-05

Web Development
In this tutorial, we'll walk through the process of building a REST API comment section for your portfolio website using Next.js and MongoDB. This powerful combination allows for a seamless integration of backend and frontend, creating a dynamic and interactive comment system for your portfolio projects or blog posts.
First, let's understand what a REST API is:
REST API (Representational State Transfer Application Programming Interface) is an architectural style for designing networked applications. It uses a stateless, client-server communication protocol, typically HTTP. REST APIs are designed to be simple, scalable, and easy to maintain. They use standard HTTP methods like GET, POST, PUT, and DELETE to perform operations on resources, which are typically represented as URLs.
Now, let's dive into building our comment section:
  1. Set up your Next.js project (if you haven't already):
npx create-next-app@latest my-portfolio --typescript cd my-portfolio
  1. Install necessary dependencies:
npm install mongodb date-fns @types/mongodb
  1. Set up MongoDB:
  • Create a MongoDB Atlas account and set up a new cluster.
  • Add your MongoDB connection string to a .env.local file in your project root:
MONGODB_URI=your_mongodb_connection_string_here
  1. Create a database connection file (lib/mongodb.ts):
import { MongoClient } from 'mongodb' if (!process.env.MONGODB_URI) { throw new Error('Invalid/Missing environment variable: "MONGODB_URI"') } const uri = process.env.MONGODB_URI const options = {} let client let clientPromise: Promise<MongoClient> if (process.env.NODE_ENV === 'development') { if (!global._mongoClientPromise) { client = new MongoClient(uri, options) global._mongoClientPromise = client.connect() } clientPromise = global._mongoClientPromise } else { client = new MongoClient(uri, options) clientPromise = client.connect() } export default clientPromise
  1. Create API routes for handling comments. In your project, create a new file: app/api/projects/[projectId]/comments/route.ts:
import { NextResponse } from 'next/server' import clientPromise from '@/lib/mongodb' import { ObjectId } from 'mongodb' export async function GET(request: Request, { params }: { params: { projectId: string } }) { const { projectId } = params const client = await clientPromise const db = client.db("portfolio") const comments = await db.collection('comments').find({ projectId }).sort({ createdAt: -1 }).toArray() return NextResponse.json(comments) } export async function POST(request: Request, { params }: { params: { projectId: string } }) { const { projectId } = params const { name, email, content } = await request.json() const client = await clientPromise const db = client.db("portfolio") const newComment = { projectId, name, email, content, createdAt: new Date() } const result = await db.collection('comments').insertOne(newComment) const insertedComment = { ...newComment, _id: result.insertedId.toString() } return NextResponse.json(insertedComment) }
  1. Create a CommentSection component (components/CommentSection.tsx):
import React, { useState, useEffect } from 'react' import { useForm } from 'react-hook-form' interface Comment { _id: string name: string content: string createdAt: string } interface CommentSectionProps { projectId: string } export function CommentSection({ projectId }: CommentSectionProps) { const [comments, setComments] = useState<Comment[]>([]) const { register, handleSubmit, reset } = useForm() useEffect(() => { fetchComments() }, [projectId]) const fetchComments = async () => { const response = await fetch(`/api/projects/${projectId}/comments`) const data = await response.json() setComments(data) } const onSubmit = async (data) => { const response = await fetch(`/api/projects/${projectId}/comments`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }) if (response.ok) { reset() fetchComments() } } return ( <div className="mt-8"> <h2 className="text-2xl font-bold mb-4">Comments</h2> <form onSubmit={handleSubmit(onSubmit)} className="mb-8"> <div className="mb-4"> <label htmlFor="name" className="block mb-2">Name:</label> <input {...register('name', { required: true })} id="name" className="w-full p-2 border rounded" /> </div> <div className="mb-4"> <label htmlFor="email" className="block mb-2">Email:</label> <input {...register('email', { required: true })} id="email" type="email" className="w-full p-2 border rounded" /> </div> <div className="mb-4"> <label htmlFor="content" className="block mb-2">Comment:</label> <textarea {...register('content', { required: true })} id="content" className="w-full p-2 border rounded" rows={4} ></textarea> </div> <button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded"> Submit Comment </button> </form> <div> {comments.map((comment) => ( <div key={comment._id} className="mb-4 p-4 bg-gray-100 rounded"> <p className="font-bold">{comment.name}</p> <p className="text-sm text-gray-500">{new Date(comment.createdAt).toLocaleString()}</p> <p className="mt-2">{comment.content}</p> </div> ))} </div> </div> ) }
  1. Integrate the CommentSection into your project page (app/projects/[projectId]/page.tsx):
import { CommentSection } from '@/components/CommentSection' export default function ProjectPage({ params }: { params: { projectId: string } }) { const { projectId } = params return ( <div> {/* Your project details here */} <CommentSection projectId={projectId} /> </div> ) }
With these steps, you'll have a fully functional REST API comment section integrated into your portfolio website. This setup allows for real-time commenting, efficient data storage with MongoDB, and a sleek UI powered by Next.js and React.
The GET and POST routes we've created follow REST principles, using standard HTTP methods to interact with our comment resources. The CommentSection component provides a form for users to submit new comments and displays existing comments for each project.
Remember to style your components to match your portfolio's design, and consider adding features like comment moderation or user authentication for a more robust system. Happy coding!