Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

สร้าง Comment System ที่ปลอดภัยสำหรับ Next.js Blog ด้วย Redis และ NextAuth

เราจะสร้าง Comment Section สำหรับ Blog ใน Tutorial นี้ Tech Stack:

  1. NextJS 13 (App Directory)
  2. NextAuth (Authentication)
  3. Upstash Redis (Store Comments)
  4. SWR (Caching และ Revalidation Comments)

Let's Start

Handling Auth with NextAuth - จัดการ Auth ด้วย NextAuth

ไม่สามารถให้ใครก็ได้ Post Comment ได้ สมควรมี Authentication System ก่อน ใช้ NextAuth

Install next-auth:

pnpm install next-auth

Directory Structure ใน App Directory:

.
├── app
│   ├── api
│   │   └── auth
│   │       └── [...nextauth]
│   │           └── route.ts
│   ├── blog
│   │   ├── page.tsx
│   │   └── [...slug]
│   │       └── page.tsx
│   ├── components
│   │   └── LoginButton.tsx
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx

Setup Auth API Route:

// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import GithubProvider from "next-auth/providers/github";
const handler = NextAuth({
  providers: [
    GithubProvider({ clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET! }),
  ],
  callbacks: {
    async session({ session, token }) {
      if (session && session.user && token.sub) { session.user.sub = token.sub; }
      return session;
    },
  },
});
export { handler as GET, handler as POST };

สร้าง Github OAuth Application ได้ GITHUB_CLIENT_ID และ GITHUB_CLIENT_SECRET

สร้าง Comment System ที่ปลอดภัยสำหรับ Next.js Blog ด้วย Redis และ NextAuth

NextAuth ให้ Sign In/Out จาก Client Component ใช้ signIn signOut จาก next-auth แต่ต้อง Setup Context Provider Wrap App ก่อน

// app/layout.tsx
"use client";
import "./globals.css";
import { SessionProvider } from "next-auth/react";
export default function RootLayout({ children, }: { children: React.ReactNode; }) {
  return ( <html lang="en"> <SessionProvider> <body>{children}</body> </SessionProvider> </html> ); }

SessionProvider ให้ Access Session State จาก Client Component ใดๆ

Access Session State 用 useSession Hook จาก next-auth ตัวอย่าง Login Button:

"use Client";
import { signIn, signOut, useSession } from "next-auth/react";
export default function LoginButton() {
  const { data: session } = useSession();
  if (session) { return ( <div> Signed in as {session.user?.name} using {session.user?.email} <br /> <button onClick={() => signOut()}>Sign out</button> </div> ); }
  return ( <div> Not signed in <br /> <button onClick={() => signIn()}> Sign in </button> </div> ); }

Auth System Ready ต่อ Server Side Routes Store Comments ใน Redis Database

Setting up Redis Database - ตั้งค่า Redis Database

  1. ไป Upstash สร้าง Redis Database
  2. เลือก Region ใกล้ Users เลือก TLS Encryption
  3. Install @upstash/redis Package: pnpm install @upstash/redis

สร้าง Comment System ที่ปลอดภัยสำหรับ Next.js Blog ด้วย Redis และ NextAuth

  1. Copy Tokens ใส่ .env.local

เขียน API Endpoints ใน Directory Structure:

.
├── app
│   ├── api
│   │   ├── auth
│   │   │   └── [...nextauth]
│   │   │       └── route.ts
│   │   ├── comment
│   │   │   ├── delete
│   │   │   │   └── route.ts
│   │   │   ├── get
│   │   │   │   └── route.ts
│   │   │   └── post
│   │   │       └── route.ts
│   │   └── lib
│   │       ├── getUser.ts
│   │       └── redis.ts
  1. Create Redis Client Instance
// app/api/lib/redis.ts
import { Redis } from "@upstash/redis";
/* Load UPSTASH_REDIS_REST_URL และ UPSTASH_REDIS_REST_TOKEN จาก Environment ด้วย process.env */
const redis = Redis.fromEnv();
export default redis;

Redis Client Ready เหลือ Setup API Routes ใน App

ใช้ Redis Lists เก็บ Comments Act as Stack Recent Comment Top แทนที่จะ Sort Client-side ใช้ Data Structure ที่ Redis มีให้

Code เต็มได้ที่นี่ Gist:

  1. Create Comment: redis.lpush(referer, comment) Push Comment ใน List Key referer
  2. Get All Comments: redis.lrange(referer, 0, -1)
  3. Delete Comment: redis.lrem(referer, 0, comment) Delete All Occurrences ของ comment ใน List Key referer

API Ready Integrate Frontend กับ Backend

Setting up the Client Side - ตั้งค่า Client Side

ไม่ยาก แค่ Hit Endpoints ที่สร้างด้วย fetch ใช้ Library swr Caching และ Revalidation Comments (React Query ก็ได้)

สร้าง useComment() Hook มี onSubmit() และ onDelete() Handlers ส่ง Requests:

"use client";
import { useState } from "react";
import type { Comment } from "@/app/interfaces/interfaces";
import useSWR from "swr";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
const useComment = () => {
  const [text, setText] = useState("");
  const { data: comments, mutate } = useSWR<Comment[]>("/api/comment/get", fetcher, { fallbackData: [] });
  const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    try { await fetch("/api/comment/post", { method: "POST", body: JSON.stringify({ text }), headers: { "Content-Type": "application/json" } }); setText(""); await mutate(); } catch (error) { console.log(error); }
  };
  const onDelete = async (comment: Comment) => {
    try { await fetch("/api/comment/delete", { method: "POST", body: JSON.stringify({ comment }), headers: { "Content-Type": "application/json" } }); await mutate(); } catch (error) { console.log(error); }
  };
  return { text, setText, comments, onSubmit, onDelete };
};
export default useComment;

Comment Section Done Fetch, Post, Delete Comments ได้ Next Steps สร้าง Components Comment Box และ Comments List Sample เต็มที่นี่