【Next.js】管理者情報をWebAPIのNextResponse,NextRequestでPOST通信を実施する

# サンプル
#### 管理者の登録画面からデータを入力します。
![管理者1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/ff40d2fa-cb50-1f32-c389-422fdea8f3fe.png)

#### 登録が成功するとPostgreSQLにデータが反映されます。
![管理者登録Postgres.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/b3415f30-accc-dfd3-2db0-76f1fcaeee5c.png)

#### 登録済み管理者の場合は、下記のようにサーバ側からメッセージを返却します。
![管理者すでにある.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/7accccb2-8f9d-9c17-cba2-19361abf1335.png)

#### アラートにて登録済みの管理者を表示する仕様です。
![管理者すでにある2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/6605f825-a290-9f17-1012-56e925dc110f.png)


# スキーマモデル
管理者情報として`AdminUser`モデルを追加しました。
```schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

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

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User{
  userId Int @id @default(autoincrement())
  userName String
  email String @unique
  password String
  createdAt DateTime @default(now())

  orders   Order[]  // 1人のユーザーは複数の注文を持つ
}

model AdminUser{
  adminUserId Int @id @default(autoincrement())
  adminUserName String
  adminEmail String @unique
  adminPassword String
  createdAt DateTime @default(now())
}

model Product{
  productId Int @id @default(autoincrement())
  productName String
  description String
  productImagepath String
  createdAt DateTime @default(now())
  updatedAt DateTime @default(now())

  items   Item[]   // 1つの製品は複数のアイテムに関連付けられる
}

model Item{
  itemId Int @id @default(autoincrement())
  quantity Int
  price Int
  createdAt DateTime @default(now())
  updatedAt DateTime @default(now())

  orderId   Int      // Order と 1対多 のリレーション
  order     Order    @relation(fields: [orderId], references: [orderId])
  productId Int      // Product と 多対1 のリレーション
  product   Product  @relation(fields: [productId], references: [productId])
}

model Order{
  orderId Int @id @default(autoincrement())
  total Int
  createdAt DateTime @default(now())
  updatedAt DateTime @default(now())

  userId    Int      // User と 1対多 のリレーション
  user      User     @relation(fields: [userId], references: [userId])
  items     Item[]   // 1つの注文には複数のアイテムが関連付けられる
}

```

# ディレクトリ構成

```
NextProject
├─ app
│  ├─ admin
│  │  ├─ userRegister
│  │  │  └─ page.tsx
│  │  └─ adminUserRegister
│  │     └─ page.tsx
│  ├─ api
│  │  ├─ adminUserRegister
│  │  │  └─ route.ts
│  │  └─ userRegister
│  │        └─ route.ts
│  ├─ components
│  │  └─ headers
│  │        └─ navbar
│  │           └─ page.tsx
│  └─ prisma
│     └─ schema.prisma
├─ next.config.ts
├─ package.json
├─ package.lock.json
└─ tailwind.config.mjs
```

# フロント側のコード

```app/admin/adminUserRegister/page.tsx
'use client'
import { useForm } from "react-hook-form"
import { useState } from "react";

//付与すること

export default function AdminRegister(){
    //初期値ｱを設定
    const defaultValues = {
        userName:'管理者太郎',
        email:'authenticater@email.com',
        password:''
    }

    //フォームを初期化する
    const {register,handleSubmit,formState:{errors}} = useForm({
        defaultValues
    });

    const [userName,setUserName] = useState("");
    const [email,setEmail] = useState("");
    const [password,setPassword] = useState("");
    
    //フォーム送信時の実行される関数
    const onSubmit = async(data:any)=>{
        //POSTリクエスト送信
        const response = await fetch('/api/adminUserRegister',{
            method:'POST',
            headers:{
                'Content-Type':'application/json',
                cache:'no-store'
            },
            body:JSON.stringify({
                userName:data.userName,
                email:data.email,
                password:data.password
            })
        });
        //レスポンスデータをJSON変換する
        const returnResponse = await response.json();
        console.log(returnResponse);

        //レスポンスを画面に表示する
        if(response.ok){
            alert('管理者ユーザ登録成功しました');
        }

        if(returnResponse.status === 500){
            alert(returnResponse.existAdminUser.adminUserName + "は、すでに塘路kされています");
        }
    }

    return(
        <div className="flex items-center justify-center min-h-screen rounded-md">
            <form onSubmit={handleSubmit(onSubmit)} className="shadow-md w-96 px-8 py-8 border border-gray-300 rounded-md">
                <div className="w-full">
                    <label className="font-bold">管理者名</label>
                    <input
                        type="text"
                        name="userName"
                        defaultValue={userName}
                        className="block rounded-md w-full text-sm border border-gray-300 text-gray-900 px-2 py-2"
                        placeholder=""
                        {...register('userName',{
                          required:'管理者名は必須です。',
                          maxLength:{
                            value:20,
                            message:'管理者名は20文字以内にしてください。'
                          }  
                        })}
                        onChange={(e)=>setUserName(e.target.value)}
                    />
                    <div className="text-red-500">{errors.userName?.message}</div>
                </div>
                <div className="w-full mt-4">
                    <label className="font-bold">管理者メールアドレス</label>
                    <input
                        type="email"
                        name="email"
                        defaultValue={email}
                        className="block rounded-md w-full text-sm border border-gray-300 text-gray-900 px-2 py-2"                        
                        {...register('email',{
                            required:'管理者メールアドレスは必須です。',
                            pattern:{
                                value:/([a-z\d+\-.]@[a-z\d-]+(?:\.[a-z]+)*)/i,
                                message:'管理写メールアドレスが必須です。'
                            }
                        })}
                        onChange={(e)=>setEmail(e.target.value)}
                    />
                </div>
                <div className="w-full mt-4">
                    <label className="font-bold">管理者パスワード</label>
                    <input
                        type="password"
                        name="password"
                        defaultValue={password}
                        className="block rounded-md w-full text-sm border border-gray-300 text-gray-900 px-2 py-2"
                        {...register('password',{
                            required:'管理者パスワードは必須です。'
                        })}
                        onChange={(e)=>{e.target.value}}
                    />
                </div>
                <div className="flex items-center justify-center mt-4 mb-4">
                    <button type="submit" className="shadow-md bg-blue-500 text-white font-bold rounded-md px-4 py-4">
                        登録
                    </button>
                </div>
            </form>
        </div>
    )
}



```

# サーバ側のコード

```app/api/adminUserRegister/route.ts
import { NextRequest,NextResponse } from "next/server";
import { PrismaClient } from "@prisma/client";
import bcrypt from 'bcryptjs'

const prisma = new PrismaClient();

export async function POST(req:NextRequest){
    try{
        let {userName,email,password} = await req.json();
        console.log("受け取った管理者名は," + userName);
        const hashedPassword:String = await bcrypt.hash(password,10);
        
        //リクエストパラメータが不足している場合はエラーレスポンスを変化ykする
        if(!userName || !email || !password){
            return NextResponse.json({error:"全ての項目を入力してください",status:401});
        }

        //登録済みユーザの確認
        const existAdminUser = await prisma.AdminUser.findUnique({
            where:{
                adminEmail: email
            }
        });

        if(existAdminUser){
            return NextResponse.json({message:"すでにこのユーザーは登録されています。",status:500,existAdminUser:existAdminUser},{status:500});
        }

        //管理ユーザを登録する
        const newAdminUser = await prisma.AdminUser.create({
            data:{
                adminUserName: userName,
                adminEmail: email,
                adminPassword: hashedPassword
            }
        });

        //成功レスポンセ鵜を変化yk数ル
        return NextResponse.json({message:'管理者ユーザーを登録しました。',adminUser:newAdminUser});

    }catch(error){
        if(error instanceof Error){
            console.log("エラー詳細：",error);
        }
        return NextResponse.json({error:"ユーザー登録中にエラーが発生しました。",status:500});
    }
}

```

以上です。