💬
Supabase Realtime APIでチャットアプリを作る
SupabaseのRealtime APIを使用して、リアルタイムチャットアプリを実装します。Realtime APIは、接続しているクライアント間でメッセージを送受信できるAPIです。
リポジトリ: https://github.com/k-logic563/supabase-chat-app
使用技術
主要パッケージ:
{
"vite": "^5.3.4",
"vue": "^3.4.31",
"typescript": "^5.2.2",
"tailwindcss": "^3.4.6",
"@supabase/supabase-js": "^2.44.4"
}
フレームワーク: Vite + Vue + TypeScript
アプリケーション概要
主な機能
- 匿名ログインで利用可能
- 他ユーザーの書き込みがリアルタイムで自動更新される
デモ

実装手順
1. データベース設定
messagesテーブルを作成します。user_idはauth.users.idを外部キーとして参照します。
create table
public.messages (
id bigint generated by default as identity,
message text not null,
created_at timestamp with time zone not null default now(),
user_id uuid not null default gen_random_uuid (),
constraint messages_pkey primary key (id),
constraint messages_user_id_fkey foreign key (user_id) references auth.users (id) on update cascade on delete cascade
) tablespace pg_default;
RLS(Row Level Security)の設定:
- RLSを有効化
-
selectとinsertに対してauthenticatedユーザーのみアクセス可能なポリシーを設定
2. 匿名ログイン画面
ユーザーを識別するために匿名ログインを実装します。signInAnonymously関数を使用します。
<!-- views/login.vue -->
<script setup lang="ts">
const handleSigninWithAnonymous = async () => {
try {
await supabaseClient.auth.signInAnonymously();
} catch (e) {
console.log(e);
}
}
</script>
3. 認証状態の管理
onAuthStateChange関数でユーザーの認証状態を監視し、適切なページにリダイレクトします。
<!-- guards/AuthGuard.vue -->
<script setup lang="ts">
const { data: authListener } = supabaseClient.auth.onAuthStateChange(
async (_: unknown, session) => {
const isLoginPage = route.path === '/login';
// セッション中にログインページにアクセスした場合、ホームへリダイレクト
if (session && isLoginPage) {
await router.push('/');
return;
}
// セッションがない場合、ログインページへリダイレクト
if (!session) {
await router.push('/login');
return;
}
}
);
onBeforeUnmount(() => {
authListener.subscription.unsubscribe();
});
</script>
4. Realtime APIの実装
channel関数でチャネルを作成し、messagesテーブルへのINSERTイベントを監視します。新しいメッセージが追加されると自動的にfetchMessageDataが実行され、画面が更新されます。
<!-- views/Home.vue -->
<script setup lang="ts">
const fetchMessageData = async () => {
try {
const { data } = await supabaseClient
.from('messages')
.select();
if (data) {
messageData.value = data;
}
} catch (e) {
console.error(e);
}
}
// 初回データ取得
fetchMessageData();
// Realtimeチャネルの設定
const channel = supabaseClient
.channel('chat')
.on(
'postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'messages' },
fetchMessageData
)
.subscribe()
// コンポーネント破棄時にチャネルを解除
onBeforeUnmount(() => {
channel.unsubscribe();
});
</script>
5. チャット一覧画面の実装
ログインユーザーのメッセージは右寄せで緑色の背景、他のユーザーのメッセージは左寄せで灰色の背景で表示します。
<!-- views/Home.vue -->
<script setup lang="ts">
const userId = ref<string>('');
onMounted(async () => {
// 現在ログイン中のユーザーIDを取得
const { data } = await supabaseClient.auth.getUser();
if (data.user) {
userId.value = data.user?.id;
}
});
</script>
<template>
<div class="max-w-[768px] mx-auto py-[32px]">
<div class="h-[calc(100vh-64px)] grid grid-rows-[auto_1fr_auto]">
<main class="p-4 bg-gray-200">
<ul v-if="messageData.length" class="flex flex-col gap-y-4 items-start">
<li
v-for="data in messageData"
:key="data.id"
:class="[
'rounded-full',
'px-4',
'py-2',
data.user_id === userId ? 'bg-green-400 ml-auto' : 'bg-gray-100'
]"
>
{{ data.message }}
</li>
</ul>
</main>
</div>
</div>
</template>
まとめ
Supabase Realtime APIを使用することで、簡単にリアルタイムチャットアプリを実装できます。
ポイント:
- Realtime機能を使うにはテーブルでRealtime onを有効化
-
channelでイベントを監視し、データベースの変更を検知 - コンポーネント破棄時に
unsubscribe()を忘れずに実行
参考
公式 Realtime API
Discussion