前回は、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
ファイルが作られます。
// 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にテーブルを作成できるかを試してみます。
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ディレクトリが作成されます。
Supabaseを見るとテーブルができたのがわかります。
データを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)で確認してみます。
無事にデータが取得できていそうです。
次にこちらのデータをフロント側で表示してみようと思います。
一旦取得できたデータを全て表示したいので、appディレクトリ配下にallusersディレクトリを作成して今回の最低限のデータ取得の型を定義しておきます。
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 />
</>
);
}
export interface UserType {
name: string;
location: string;
image: string;
bio: string;
}
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>
);
}
無事に表示表示できました!🎉
とりあえず、この後は全て記事にするのはしませんが、必要なAPIを開発していきます!✌️