Next.js

[Next.js] Next.js 공식문서 6장 데이터베이스 설정 에러 해결

배트리버 2024. 11. 26. 23:32
Next.js 공식문서 6장 '데이터베이스 설정'을 따라하던 도중 여러 문제에 직면했다. 순조롭게 레포지토리 생성 및 vercel 배포까지 완료하였는데 데이터베이스를 연동하는 과정에서 에러가 발생해 이것 저것 찾아보면서 나와 비슷한 고민을 하고 있는 사람들을 위해 오늘 포스트를 작성해보겠다. 

 

현재 공부중인 공식문서는 6장 데이터 베이스 설정이다. 

https://nextjs.org/learn/dashboard-app/setting-up-your-database

 

Learn Next.js: Setting Up Your Database | Next.js

Setup a database for your application and seed it with initial data.

nextjs.org

 

모두 순조롭게 깃허브에서 레포지토리를 생성하고 vercel을 가입하고 배포하는 것 까진 어렵지 않았을 것이다. 

발생한 문제와 해결 방법

 

1. PostgreSQL Database .env.local 복사 

해결 방법 :  .env.example 파일명 ->   .env 로 변경하기

여기서 파일 구조를 보면 .env.example 파일이 존재하는데 무심코 아무생각 없이 그 파일에 .env.local 에 있는 코드 스니팻을 모두 복사해 붙여넣었더니 에러가 발생하였다.  아래 설명에도 나와있듯 파일 이름을 .env 로 변경하라고 나와있지만 제대로 읽지 않은 잘못이 크다 .. ! 

 

2. http://localhost:3000/seed 실행 

해결 방법 : 주석 해제 후 return 문  제거하기 

import bcrypt from 'bcrypt';
import { db } from '@vercel/postgres';
import { invoices, customers, revenue, users } from '../lib/placeholder-data';

const client = await db.connect();

async function seedUsers() {
  await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
  await client.sql`
    CREATE TABLE IF NOT EXISTS users (
      id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
      name VARCHAR(255) NOT NULL,
      email TEXT NOT NULL UNIQUE,
      password TEXT NOT NULL
    );
  `;

  const insertedUsers = await Promise.all(
    users.map(async (user) => {
      const hashedPassword = await bcrypt.hash(user.password, 10);
      return client.sql`
        INSERT INTO users (id, name, email, password)
        VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
        ON CONFLICT (id) DO NOTHING;
      `;
    }),
  );

  return insertedUsers;
}

async function seedInvoices() {
  await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;

  await client.sql`
    CREATE TABLE IF NOT EXISTS invoices (
      id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
      customer_id UUID NOT NULL,
      amount INT NOT NULL,
      status VARCHAR(255) NOT NULL,
      date DATE NOT NULL
    );
  `;

  const insertedInvoices = await Promise.all(
    invoices.map(
      (invoice) => client.sql`
        INSERT INTO invoices (customer_id, amount, status, date)
        VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
        ON CONFLICT (id) DO NOTHING;
      `,
    ),
  );

  return insertedInvoices;
}

async function seedCustomers() {
  await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;

  await client.sql`
    CREATE TABLE IF NOT EXISTS customers (
      id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
      name VARCHAR(255) NOT NULL,
      email VARCHAR(255) NOT NULL,
      image_url VARCHAR(255) NOT NULL
    );
  `;

  const insertedCustomers = await Promise.all(
    customers.map(
      (customer) => client.sql`
        INSERT INTO customers (id, name, email, image_url)
        VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
        ON CONFLICT (id) DO NOTHING;
      `,
    ),
  );

  return insertedCustomers;
}

async function seedRevenue() {
  await client.sql`
    CREATE TABLE IF NOT EXISTS revenue (
      month VARCHAR(4) NOT NULL UNIQUE,
      revenue INT NOT NULL
    );
  `;

  const insertedRevenue = await Promise.all(
    revenue.map(
      (rev) => client.sql`
        INSERT INTO revenue (month, revenue)
        VALUES (${rev.month}, ${rev.revenue})
        ON CONFLICT (month) DO NOTHING;
      `,
    ),
  );

  return insertedRevenue;
}

export async function GET() {
  // return Response.json({  <-- 이 부분 제거하기 
  //   message:
  //     'Uncomment this file and remove this line. You can delete this file when you are finished.',
  // });
  try {
    await client.sql`BEGIN`;
    await seedUsers();
    await seedCustomers();
    await seedInvoices();
    await seedRevenue();
    await client.sql`COMMIT`;

    return Response.json({ message: 'Database seeded successfully' });
  } catch (error) {
    await client.sql`ROLLBACK`;
    return Response.json({ error }, { status: 500 });
  }
}
문서만 읽었을 땐 seed/route.ts 파일에 있는 주석처리만 모두 해제하면 " Database seeded successfully " 문구가 떠야되는데 안떠서 코드를 자세히 다시 보니 return 이후로 코드가 실행되지 않기 때문에 그 부분을 삭제해주니 제대로 실행이 되었다 .. ! 
(심지어 message에도 삭제하라고 나와있다.. ! )

 

3. 쿼리 실행 

해결 방법 :  query/route.ts 파일 생성 후 쿼리 작성 

import { db } from '@vercel/postgres';

export async function GET() {
  const client = await db.connect();

  const result = await client.sql`
    SELECT invoices.amount, customers.name
    FROM invoices
    JOIN customers ON invoices.customer_id = customers.id
    WHERE invoices.amount = 666;
  `;

  return Response.json(result.rows);
}

 

제공된 폴더에서는 query/route.ts 파일이 없어서 직접 만들어서 실행해보았다.  파일을 생성하고 query 주소로 이동해보면 "Evil Rabbit" 이 정답임을 알 수 있다.