STAY INFORMED
following content serves as a personal note and may lack complete accuracy or certainty.

Minimal-Mistakes instruction
Useful vscode Shortcut Keys
Unix Commands
npm Commands
Vim Commands
Git Note
Useful Figma Shortcut Keys

2 minute read

Auth

I created auth directory and created login, signup, logout pages and api routes.

des1

des3

To store user’s data, I used MySQL with Prisma.

npm install prisma @prisma/client
npx prisma init

Changed prisma file

// prisma/schema.prisma
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

// Define User
model User {
  id       Int    @id @default(autoincrement())
  email    String @unique
  password String
  nickname String
}

and migrated

npx prisma migrate dev --name init
# after --name is like comment(optional)

If you have changed prisma file you have to migrate again and generate prisma client

npx prisma generate

and install bcyrpt for hashing password

npm install bcrypt

Sign Up

In Next.js, if you use App Router and you want to use react components, you need this line. I added it at very top.

"use client";
Client Side

Implemented InputField

const InputField = ({ label, type, value, onChange, error400, error409 }) => {
  return (
    <>
      <div className="m-5">
        <label>{label}</label>
        <input
          className="text-blue-500"
          type={type}
          value={value}
          onChange={onChange}
        />

        <span className={`text-red-500 ${error400 ? "" : "hidden"}`}>
          {error400}
        </span>
        <span className={`text-red-500 ${error400 ? "" : "hidden"}`}>
          {error409}
        </span>
      </div>
    </>
  );
};

useState

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [nickname, setNickname] = useState("");
const [error400, setError400] = useState([]);
const [error409, setError409] = useState([]);

form submit function

const handleSubmit = async (e) => {
  e.preventDefault();
  setErrors([]); // reset errors

  const res = await fetch("/api/auth/signup", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ email, password, nickname }),
  });

  const data = await res.json(); // get data from api

  if (res.ok) {
    console.log(`success ${JSON.stringify(data)}`);
  } else {
    // check 400 error first
    if (res.status === 400) {
      setError400(data.errors);
    }
    // then check 409 error
    else if (res.status === 409) {
      setError409(data.errors);
    }
  }
};
Server Side

Import what I need and initialize prisma client.

import { NextResponse } from "next/server";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcrypt";

const prisma = new PrismaClient();

I distinguish 400, 409 errors.

if 400 error that at least one required field is empty, return that first and next check 409 error that there is a duplicated email or nickname.

const body = await req.json();
const { email, nickname, password, confirmPassword } = body;
const error400 = [];
const error409 = [];
 try {
    if (!email) {
      error400.push("email");
    }
    if (!nickname) {
      error400.push("nickname");
    }
    if (!password) {
      error400.push("password");
    } else if (password != confirmPassword) {
      error400.push("confirmPassword");
    }

    // if at least one required field is empty, return bad request
    if (error400.length > 0) {
      return NextResponse.json({ errors: error400 }, { status: 400 });
    }

    const existingUser = await prisma.user.findMany({
      where: {
        OR: [{ email }, { nickname }],
      },
    });

    if (existingUser.length > 0) {
      existingUser.forEach((user) => {
        if (user.email === email) {
          error409.push("email");
        }
        if (user.nickname === nickname) {
          error409.push("nickname");
        }
      });
    }

    // if there is at least one error, return conflict
    if (error409.length > 0) {
      return NextResponse.json({ errors: error409 }, { status: 409 });
    }

If all good, return 201

// hash password
const hashedPassword = await bcrypt.hash(password, 10);

// create user
const user = await prisma.user.create({
  data: {
    email,
    password: hashedPassword,
    nickname,
  },
});

// return created request
return NextResponse.json({ message: "success", user }, { status: 201 });

and disconnect prisma to prevent memory leak.

finally {
    // to prevent memory leak
    await prisma.$disconnect();
  }

Login