Clerkとsupabaseを使いテキストと画像を投稿できるような機能を作る
こんにちは
webアプリ開発でclerkとsupabaseを使い記事と画像をuploadできるような機能を作ったのでアウトプットします。
最も公式ドキュメントを少し弄っただけですが...日本語向けにはあまりなさそうなので書き記しておきます。
二回目の初投稿なので拙いと思いますがご容赦ください。
Clerkとは
爆速で認証機能を実装できるやばいBaaSサービス
supabaseとは
firebaseの代替として注目されているBaaSサービス
一応supabaseにもAuth機能はありますがそっちはまだ試せてなく...しかし認証機能だけならClerkが爆速だと思いますので多分この組み合わせが一番早いと思います。
環境や使用する技術
NextJS:15.0.3
Clerk (認証)
supabase (DB,Storage)
Clerkの設定をしよう
ClerkのトップページでGitかGoogleでログインしたら
このようなページになると思います。
そうなんです。トグルをクリックするだけでoAuth認証を付けれます!爆速すぎる!
今回はGoogleとDiscordにしましょうか。
Next.JSの導入は省略します。
次の画面に進んだら手順が書かれてますので手順に従ってコピペしていってください。
layout.tsxだけimport { ClerkProvider } from '@clerk/nextjs'
だけimportし、<ClerkProvider>で包んでください。
因みにまだ実験段階のようですが日本語にすることもできます。
その場合は
npm install @clerk/localizations
をインストールし、下記のlayout.tsxに
import { jaJP } from '@clerk/localizations'
{/*中略*/}
<ClerkProvider>
<ClerkProvider localization={jaJP}>{/*日本語対応させたないならこちら*/}
<html lang="en">
<body>
{children}
</body>
</html>
</ClerkProvider>
開発サーバーは立ち上げなくてもいいと思います。
終わったらこちらのボタンをクリックしてまた引き続きコピペしていってください。
そしてすべて終わって開発サーバーを立ち上げると
できましたね。何もCSS当ててないので隅に寄ってますがまぁいいでしょう。
googleかdiscordでログインしたらNextJSのデフォルトのページに飛ぶと思います!
ただこのままだとログアウトできないので適当な場所に<UserButton/>を追記しておきましょう。
import Image from "next/image";
import styles from "./page.module.css";
import { SignedIn, UserButton } from '@clerk/nextjs';
export default function Home() {
return (
<div className={styles.page}>
<UserButton />
<main className={styles.main}>
これで認証周りは一段落ですね!
supabaseを設定しよう
続いてsupabaseの設定を行います。
supabase
GitHubなどでログインしdashboardに行き、NewProjectでプロジェクトを作成してください。
ここからはClerk側の公式ドキュメントを参考にしてください。
ほんとは一から手順を説明したいのですがそこまで時間がなく...
ただ画像をStorageに保存した際に発行されるPathを保存するためのカラムを追加する必要がある為、二番目のステップで
create table tasks(
id serial primary key,
name text not null,
user_id text not null default requesting_user_id(),
image_url text not null
);
-- Enable RLS on the table
alter table "tasks" enable row level security;
と、クエリしてください。
また3番目の手順ではDELETEpolicyもSELECTと同様の手順で設定してください。
8番まで進めましたら一旦ストップしましてStorageのバケットを作っていきます。
supabaseの左のメニューからStorageを選びNewBacketから新規作成しましょう。
Public bucketをオンにしましょう。
Additional configurationからは送信時の容量の制限やファイル形式の制限ができるみたいです。
容量はデフォルトだとすごく小さいので5MB
くらいにしておきましょう。
そしてPoliciesをクリックしPolicy設定します。
Policy name にAllow authenticated uploads
Allowed operationでINSERT
にチェック
Target rolesにauthenticated
Policy definitionに
(bucket_id = 'tasks_image'::text)
を張り付けてreviewをクリックし保存しましょう。
そして私のリポジトリにdemoがあり、そこに私がテストで作ったapp/page.tsxを公開していますので
コピペなりなんなりしてください。
尚、material UIを使ってwebアプリ開発しているので
npm install @mui/material @emotion/react @emotion/styled --legacy-peer-deps
npm install @mui/icons-material --legacy-peer-deps
を実行してください。
--legacy-peer-deps
オプションはmaterial UIがreact19に対応していなかったのでつけました。
バージョンに寄るのでお好みで。
material UIについては今後何かしらで触れたいと思います。
const fileName = `${crypto.randomUUID()}`
const { error: upError } = await client.storage
.from('tasks_image')
.upload(fileName, imageFile)
randomUUIDを使ってローカルのファイル名をそのままStorageにあげないようにし.uploadで引数として渡してあげます。
const { data: urlData } = await client.storage
.from('tasks_image')
.getPublicUrl(fileName)
await client.from('tasks').insert({
name,
image_url: urlData?.publicUrl,
})
getPublicUrlでStorageに保存したパスを取得し、insert時にimage_urlに挿入できるようにしました。
実際に動かすとこうしてテキストと画像を表示させることができます。
ここから応用が色々効きそうですね。
まとめ
意外と簡単にできたと思います。
途中で飽きたのでどこか説明が抜けてるところがあるかもしれません。
ほなまた
Discussion