1
1

【個人開発_#4】SupabaseとPrismaを導入してデータの永続化

Posted at

前回は、Googleログインを実装しました。
今回は、SupabaseとPrismaを導入してデータの永続化(保存)ができるようにしていきます。

Supabaseの導入

Supabaseとは?

  • オープンソースのリアルタイムデータベース
  • バックエンドの機能を提供するプラットフォーム
  • PostgreSQLデータベースがベース
  • 開発者はサーバーサイドのコードを書かずにバックエンドの機能をそのえたアプリケーションの構築が可能

Supabaseの導入

公式サイトで登録を行います。

Prismaのインストール

PrismaはNode.jsのORMの1つです。

公式ドキュメントに沿ってインストールを行います。

$ pnpm install prisma --save-dev

Dockerのコンテナ内でインストールを実行するために...

  • コンテナ内にアクセスします
    docker-compose exec app sh
  • prismaをインストールします
    pnpm add prisma --save-dev

実際に、Next.jsからデータを追加・削除するにはPrisma Clientが必要になるのでインストールします。

pnpm install @prisma/client

Prismaを初期化します。

npx prisma init

Next.jsのプロジェクトにprismaフォルダが追加されてschema.prismaファイルが作られます。
CleanShot 2024-07-17 at 08.33.54@2x.jpg

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")
}

.envファイルにDATABASE_URLが追加されます。

DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"

ここをSupabase作成時のデータベースのURLに変更します。

次に、スキーマを設定します。まずは、最低限のスキーマを登録してSupabaseにテーブルを作成できるかを試してみます。

schema.prisma
model User {
  id Int @id @default(autoincrement())
  name String
  date DateTime @default(now())
  image String
  currentAddress String
  bio String
}

スキーマの設定後、マイグレーションを実行してSupabaseにテーブルを作成します。

$ npx prisma init

✔ Your Prisma schema was created at prisma/schema.prisma
  You can now open it in your favorite editor.

warn Prisma would have added DATABASE_URL but it already exists in .env
warn You already have a .gitignore file. Don't forget to add `.env` in it to not commit any private information.

Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb.
3. Run prisma db pull to turn your database schema into a Prisma schema.
4. Run prisma generate to generate the Prisma Client. You can then start querying your database.
5. Tip: Explore how you can extend the ORM with scalable connection pooling, global caching, and real-time database events. Read: https://pris.ly/beyond-the-orm

More information in our documentation:
https://pris.ly/d/getting-started

マイグレーションを実行します。

npx prisma migrate dev --name init

prismaディレクトリ配下にmigrationsディレクトリが作成されます。
CleanShot 2024-07-24 at 06.33.27@2x.jpg

Supabaseを見るとテーブルができたのがわかります。
CleanShot 2024-07-17 at 09.28.22@2x.jpg
データをGUIから適当に入力しておきます。

APIでエンドポイントを作成
appディレクトリ配下にapi/usersフォルダを作成して、route.tsを作成します。
データベースを操作するために、prismaのインスタンスを作成します。

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

const prisma = new PrismaClient();

export async function main() {
  try {
    await prisma.$connect();
  } catch (error) {
    return Error('Failed to connect to database');
  }
}

export const GET = async (req: Request, res: Response) => {
  try {
    await main();
    const users = await prisma.user.findMany();
    return NextResponse.json(users, { status: 200 });
  } catch (err) {
    return NextResponse.json({ message: 'Server error', err }, { status: 500 });
  } finally {
    await prisma.$disconnect();
  }
};

これでAPIの作成は完了です。
APIを確認するツール(今回はVSCodeの拡張機能Thunder Client)で確認してみます。
CleanShot 2024-07-24 at 06.40.52@2x.jpg
無事にデータが取得できていそうです。

次にこちらのデータをフロント側で表示してみようと思います。
一旦取得できたデータを全て表示したいので、appディレクトリ配下にallusersディレクトリを作成して今回の最低限のデータ取得の型を定義しておきます。

app/allusers/page.tsx
import Footer from '@/components/Footer';
import Header from '@/components/Header';
import ProfileCard from '@/components/ProfileCard';
import Image from 'next/image';
import { UserType } from '@/app/type';

async function fetchAllUsers() {
  const res = await fetch('http://localhost:3000/api/users', {
    cache: 'no-cache',
  });

  return res.json();
}

export default async function Page() {
  const users: UserType[] = await fetchAllUsers();

  return (
    <>
      <Header />
      <div className="px-4">
        <div className="flex items-center text-2xl">
          <Image src="/images/icon-member.svg" alt="" width={40} height={40} />
        </div>

        <div className="mt-10">
          {users.map((user: UserType, index: number) => (
            <ProfileCard key={index} {...user} />
          ))}
        </div>
      </div>
      <Footer />
    </>
  );
}
app/type.d.ts
export interface UserType {
  name: string;
  location: string;
  image: string;
  bio: string;
}
components/ProfileCard/index.tsx
import Link from 'next/link';
import { UserType } from '@/app/type';

export default function ProfileCard({ name, location, image, bio }: UserType) {
  return (
    <Link href="#" className="block bg-white rounded-lg shadow-md p-6 mb-4">
      <div className="flex items-center">
        <img src={image} alt={name} className="w-16 h-16 object-cover rounded-full mr-4" />
        <div>
          <h2 className="text-xl font-bold">{name}</h2>
          <p className="text-gray-600">{location}</p>
        </div>
      </div>
      <p className="mt-4 text-gray-800">{bio}</p>
    </Link>
  );
}

CleanShot 2024-07-24 at 06.49.43@2x.jpg

無事に表示表示できました!🎉
とりあえず、この後は全て記事にするのはしませんが、必要なAPIを開発していきます!✌️

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1