Slide 1

Slide 1 text

オトナのプログラミング勉強会 【Supabase×React】サーバレスアプリ開発入門 2023.07.12 新垣圭祐(ソーイ株式会社 / YOKUMIRU株式会社) 【Supabase×React】サーバレスアプリ開発入門 1

Slide 2

Slide 2 text

新垣圭祐 (ソーイ株式会社 / YOKUMIRU株式会社) Web/モバイルアプリ開発エンジニア → PdM 大学院で自律分散コンピューティングの研究 インドに渡り現地システム会社にて勤務 帰国してフリーランスエンジニア → 会社設立 認定スクラムマスター/プロダクトオーナー 興味 アジャイル開発、プロダクトマネジメント Web3 趣味 格闘技(柔術) 【Supabase×React】サーバレスアプリ開発入門 2

Slide 3

Slide 3 text

ソーイ株式会社(ソフトウェアパッケージと受託開発の会社) YOKUMIRU株式会社(オンライン医療相談サービスを提供する事業会社) 【Supabase×React】サーバレスアプリ開発入門 3

Slide 4

Slide 4 text

アジェンダ Supabaseとは ハンズオン Supabaseのアーキテクチャ まとめ 【Supabase×React】サーバレスアプリ開発入門 4

Slide 5

Slide 5 text

Supabase Supabase is an open source Firebase alternative. サーバーレスのバックエンドサービス(Firebase Alternative: Firabaseの代替) 全てがオープンソース PostgreSQL(RDS)(⇔ FirebaseはNoSQL) 2019年より開発 【Supabase×React】サーバレスアプリ開発入門 5

Slide 6

Slide 6 text

利用イメージ 従来の開発 1. クライアントがバックエンドにリクエスト を送信 2. バックエンドで認可、バリデーション、ト ランザクション等を必要に応じてハンドリ ング 3. バックエンドがデータベースにアクセスし てデータを取得して、フロントエンドに返 却する 【Supabase×React】サーバレスアプリ開発入門 6

Slide 7

Slide 7 text

Supabaseを利用した開発 1. クライアントが直接データベースにリクエ ストを送信 2. データベースで認可、バリデーション、ト ランザクション等を必要に応じてハンドリ ングし、データを取得して、フロントエン ドに返却する 実際はSupabaseがバックエンドの処理を行っ ているが開発からは見えないようになっている 【Supabase×React】サーバレスアプリ開発入門 7

Slide 8

Slide 8 text

Supabaseの提供する機能(バックエンド) Database(データベース) PosgreSQL リアルタイム機能 Authenticaton(認証) ユーザー認証(登録・ログイン) データへのセキュアなアクセス(Row Level Security) Storage(ストレージ) Edge Functions(関数) Denoを使った実行環境 主に外部APIとの連携に利用する 【Supabase×React】サーバレスアプリ開発入門 8

Slide 9

Slide 9 text

Supabaseのクライアントライブラリ(フロントエンド) 豊富なクライアントライブラリ 公式 JavaScript, TypeScript, Flutter コミュニティにより提供 Kotlin, Swift, Ruby, C# 【Supabase×React】サーバレスアプリ開発入門 9

Slide 10

Slide 10 text

ハンズオン 【Supabase×React】サーバレスアプリ開発入門 10

Slide 11

Slide 11 text

Next.jsのプロジェクトの作成 $ npx create-next-app What is your project named? otona-hans-on Would you like to use TypeScript with this project? … No Would you like to use ESLint with this project? … No Would you like to use Tailwind CSS with this project? … Yes Would you like to use src/ directory with this project? … No Use App Router (recommended)? … Yes Would you like to customize the default import alias? … No 【Supabase×React】サーバレスアプリ開発入門 11

Slide 12

Slide 12 text

Next.jsの動作を確認 $ cd otona-hans-on // supabase-js のインストール $ npm install @supabase/supabase-js // Next.js の起動 $ npm run dev http://localhost:3000を開く 【Supabase×React】サーバレスアプリ開発入門 12

Slide 13

Slide 13 text

app/global.css 4行目以降を削除する @tailwind base; @tailwind components; @tailwind utilities; app/page.js 下記内容に置き換える export default function Home() { return (
ハンズオンのスタート
) } 【Supabase×React】サーバレスアプリ開発入門 13

Slide 14

Slide 14 text

Supabaseプロジェクトの作成と接続 【Supabase×React】サーバレスアプリ開発入門 14

Slide 15

Slide 15 text

SupabaseのDashboardから「New Project」 Name: otona hans-on Database Password: (「Generate a passowrd」をクリック) Region: Northeast Asia (Tokyo) Pricing Plan: Free 【Supabase×React】サーバレスアプリ開発入門 15

Slide 16

Slide 16 text

Project Settings > API > API Settingsを 開く 1. Project API Keysのanon publicをコピー 2. Project ConfigurationのURLをコピー Next.jsのプロジェクト直下に.env.localフ ァイルを作成 NEXT_PUBLIC_SUPABASE_URL= (1 を貼り付け) NEXT_PUBLIC_SUPABASE_ANON_KEY= (2 を貼り付け) 【Supabase×React】サーバレスアプリ開発入門 16

Slide 17

Slide 17 text

SQL Editor > + New query > New blank queryをクリ ック 以下の内容を貼り付けてRUNをクリック create table todos ( id bigint generated by default as identity primary key, user_id uuid references auth.users not null, task text not null, is_complete boolean default false, inserted_at timestamp with time zone default timezone('utc'::text, now()) not null ); 【Supabase×React】サーバレスアプリ開発入門 17

Slide 18

Slide 18 text

ログイン画面の表示 app/page.js export default function Home() { return (
マジックリンクでログイン
) } 【Supabase×React】サーバレスアプリ開発入門 18

Slide 19

Slide 19 text

ログイン処理を追加 Supabaseクライアントを作成 (use clientでクライアントコンポーネントであることを明示する) 'use client' import {createClient} from '@supabase/supabase-js'; const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, ) 【Supabase×React】サーバレスアプリ開発入門 19

Slide 20

Slide 20 text

Home()内にログイン処理を追加 const handleLogin = async (e) => { e.preventDefault() const form = e.currentTarget const { email } = Object.fromEntries(new FormData(form)) if (typeof email === 'string') { await supabase.auth.signInWithOtp({ email }) alert('Email に認証リンクが送信されました') } } ボタンを押した時にhandleLogin()が呼ばれるようにする ... ... 【Supabase×React】サーバレスアプリ開発入門 20

Slide 21

Slide 21 text

Home()内にログインユーザを取得する処理を追加 // ユーザーを保持する関数 const [user, setUser] = useState(null) useEffect(() => { // ログイン状態の確認 const getInitialUser = async () => { const { data: { user }, } = await supabase.auth.getUser() console.log(user) setUser(user) } getInitialUser() }, []) 【Supabase×React】サーバレスアプリ開発入門 21

Slide 22

Slide 22 text

ログインユーザの表示 return ( {user ? ( // ログイン済みの表示
Hello, {user.id}
) : ( // 未ログイン時の表示
(略、フォーム部分)
)} ) 【Supabase×React】サーバレスアプリ開発入門 22

Slide 23

Slide 23 text

データの挿入(insert) // 新しいタスクを`todos` テーブルに挿入 const handleSubmit = async (e) => { e.preventDefault() const form = e.currentTarget const { task } = Object.fromEntries(new FormData(form)) // データのバリデーション if (typeof task === 'string' && task.length !== 0) { form.reset() // `todos` テーブルにデータを格納 await supabase.from('todos').insert({ user_id: user.id, task: task }) } } 【Supabase×React】サーバレスアプリ開発入門 23

Slide 24

Slide 24 text

表示部分の作成 ...
Hello, {user.id}
... Supabase管理画面のTable Editorでデータが追加され ていることを確認 【Supabase×React】サーバレスアプリ開発入門 24

Slide 25

Slide 25 text

データの取得(select) ページを表示した時にデータを取得する処理を追加 const [user, setUser] = useState(null) const [todos, setTodos] = useState([]) // 追加 useEffect(() => { // (略) const getInitialMessages = async () => { const { data, error } = await supabase .from('todos') .select() .order('inserted_at', { ascending: false }) console.log(data) if (error) { alert(error.message) } else if (data) { setTodos(data) } } getInitialMessages() }, []) 【Supabase×React】サーバレスアプリ開発入門 25

Slide 26

Slide 26 text

表示部分 // (略)
Hello, {user.id}
    {todos.map((todo) => (
  • {todo.task}
    {new Date(todo.inserted_at).toLocaleDateString('ja')}
  • ))}
// (略) 【Supabase×React】サーバレスアプリ開発入門 26

Slide 27

Slide 27 text

データの更新(update) // チェックアイコンをクリックした時に`is_comprete` ステータスをアップデート const handleUpdate = async (taskId, newStatus) => { await supabase .from('todos') .update({ is_complete: newStatus }) .eq('id', taskId) .select() } 【Supabase×React】サーバレスアプリ開発入門 27

Slide 28

Slide 28 text

iconのインストール $ npm install @heroicons/react 表示部分
  • {/* ここから追加*/} handleUpdate(todo.id, !todo.is_complete)} > {/* ここまで*/}
    {todo.task}
    {new Date(todo.inserted_at).toLocaleDateString('ja')}
  • 【Supabase×React】サーバレスアプリ開発入門 28

    Slide 29

    Slide 29 text

    データの削除(delete) const handleDelete = async (taskId) => { await supabase .from('todos') .delete() .eq('id', taskId) } 【Supabase×React】サーバレスアプリ開発入門 29

    Slide 30

    Slide 30 text

    表示部分
  • handleUpdate(todo.id, !todo.is_complete)} >
    {todo.task}
    {new Date(todo.inserted_at).toLocaleDateString('ja')}
    {/* ここから追加*/} handleDelete(todo.id)} > {/* ここまで*/}
  • 【Supabase×React】サーバレスアプリ開発入門 30

    Slide 31

    Slide 31 text

    ここまでのpage.jsの内容 https://gist.github.com/kei4eva4/0c32432e4605dfe5b31d30a68ebed799#file-1-page-js 【Supabase×React】サーバレスアプリ開発入門 31

    Slide 32

    Slide 32 text

    リアルタイム機能の利用 Database > todos(テーブルを選んで) Editをクリック Enable Realtimeにチェックを入れてSave をクリック 【Supabase×React】サーバレスアプリ開発入門 32

    Slide 33

    Slide 33 text

    データの追加(insert)をリアルタイムで反映させる useEffect(() => { // 略 supabase.channel('todos-channel') .on( 'postgres_changes', { event: 'INSERT', schema: 'public', table: 'todos' }, (payload) => { setTodos((prev) => [payload.new, ...prev]) } ) .subscribe() // 略 }, []) タスクを追加したら、リアルタイムで反映されることを確認する 【Supabase×React】サーバレスアプリ開発入門 33

    Slide 34

    Slide 34 text

    データの更新(update)、データの削除(delete)をリアルタイムで反映させる supabase.channel('todos-channel') .on( 'postgres_changes', { event: 'INSERT', schema: 'public', table: 'todos' }, (payload) => { setTodos((prev) => [payload.new, ...prev]) } ) .on( 'postgres_changes', { event: 'UPDATE', schema: 'public', table: 'todos' }, (payload) => { setTodos((prev) => { const updatedTodo = payload.new const targetIndex = prev.findIndex( (todo) => todo.id === updatedTodo.id ) if (targetIndex >= 0) { prev[targetIndex] = updatedTodo } return [...prev] }) } ) .on('postgres_changes', { event: 'DELETE', schema: 'public', table: 'todos' }, (payload) => { setTodos((prev) => prev.filter((todo) => todo.id !== payload.old.id) ) } ).subscribe() 【Supabase×React】サーバレスアプリ開発入門 34

    Slide 35

    Slide 35 text

    Row Level Security (RLS) について Supabaseでは、PostgreSQLのRLS(行単位セキュリティ)を利用することにより細かい認可ルールを設定 することができる PoliciesはPostgreSQLのルールエンジンで、複雑で柔軟なルール設定を記述することが可能 Policies(ポリシー)の例 自分のTodoのみ表示が可能 create policy "Individuals can view their own todos." on todos for select using ( auth.uid() = user_id ); データ取得(slect)の度に、次のように変換される select * from todos where auth.uid() = todos.user_id; -- Policy is implicitly added. 【Supabase×React】サーバレスアプリ開発入門 35

    Slide 36

    Slide 36 text

    RLSを利用する 【Supabase×React】サーバレスアプリ開発入門 36

    Slide 37

    Slide 37 text

    ログアウト機能をつける const handleLogout = async () => { await supabase.auth.signOut() } 表示部分
    Hello, {user.id}
    ログアウト
    【Supabase×React】サーバレスアプリ開発入門 37

    Slide 38

    Slide 38 text

    自分のタスクか他の人のタスクかラベルをつけ る
    {todo.task}
    {new Date(todo.inserted_at).toLocaleDateString('ja')}
    {/* ここから追加*/}
    { todo.user_id === user.id ? ' 私のタスク' : ' 他人のタスク'}
    {/* ここまで*/}
    ここまでのpage.jsの内容 https://gist.github.com/kei4eva4/0c32432e4605dfe5b31d 30a68ebed799#file-2-page-js 【Supabase×React】サーバレスアプリ開発入門 38

    Slide 39

    Slide 39 text

    Row Level Security (RLS) の 利用 Database > todos(テーブルを選んで) Editをクリック Enable Row Level Securityにチェックを入 れてSaveをクリック 【Supabase×React】サーバレスアプリ開発入門 39

    Slide 40

    Slide 40 text

    RLSを有効化すると、アクセス不可になる Policies(ポリシー)を設定してデータを取り扱えるよ うにする 【Supabase×React】サーバレスアプリ開発入門 40

    Slide 41

    Slide 41 text

    Plicies(ポリシー)を作成 Authentication > Policies > New Policy > For full customizationをクリック 【Supabase×React】サーバレスアプリ開発入門 41

    Slide 42

    Slide 42 text

    Plicy name: Individuals can view their own todos. Allowed operation: SELECT USING expression: (auth.uid() = user_id) Review > Save pliciyをクリック 【Supabase×React】サーバレスアプリ開発入門 42

    Slide 43

    Slide 43 text

    自分のタスクのみ表示されるようになっている 【Supabase×React】サーバレスアプリ開発入門 43

    Slide 44

    Slide 44 text

    SQL Editor > + New query > New blank queryをクリック 挿入(insert)、更新(update)、削除 (delete)についてはSQL Editorから同様 に作成する 以下の内容を貼り付けてRUNをクリック create policy "Individuals can create todos." on todos for insert with check (auth.uid() = user_id); create policy "Individuals can update their own todos." on todos for update using (auth.uid() = user_id); create policy "Individuals can delete their own todos." on todos for delete using (auth.uid() = user_id); 【Supabase×React】サーバレスアプリ開発入門 44

    Slide 45

    Slide 45 text

    RLSが追加されていることを確認 RLSが無効の時と同様に挿入、更新、削除 ができることを確認 【Supabase×React】サーバレスアプリ開発入門 45

    Slide 46

    Slide 46 text

    ハンズオンはここまでです 【Supabase×React】サーバレスアプリ開発入門 46

    Slide 47

    Slide 47 text

    Supabaseのアーキテクチャ Supabaseは複数のOSSツールによって構 成されている 【Supabase×React】サーバレスアプリ開発入門 47

    Slide 48

    Slide 48 text

    PostgreSQL (Database) Supabaseのコア カスタマイズはしていない(ユーザーは全ての機能にアクセスできる) SupabaseはPostgreSQLを使いやすくするためのツールを提供している GoTrue (Auth) 認証API、アクセストークンの払い出し RLS連携 Supabaseが開発しているOSS(Netlifyからのフォーク) Golang 【Supabase×React】サーバレスアプリ開発入門 48

    Slide 49

    Slide 49 text

    PostgREST (API) PostgreSQLのREST APIが自動生成される APIでテーブル操作が可能 Haskell Realtime (API & multiplayer) メッセージのブロードキャスト データベース変更をストリーミング可能にする Websocket Elixir 【Supabase×React】サーバレスアプリ開発入門 49

    Slide 50

    Slide 50 text

    Storage API (large file storage) AWS S3互換のストレージ 権限制御はGoTrueの発行したToken TypeScript Deno (Edge Functions) JavaScript/TypeScriptのランタイム TypeScript/Rust 【Supabase×React】サーバレスアプリ開発入門 50

    Slide 51

    Slide 51 text

    まとめ Supabaseとは Firebaseの代替 全てOSSを組み合わせて構成されている 使いやすいフロントエンド、モバイルクライアントを提供 ハンズオン データベースの作成 リアルタイム機能(サブスクリプション) Row Level Security(RLS) Supabaseのアーキテクチャ 生のPostgreSQLを使いやすくするツールを提供 他のOSSを組み合わせて構成されている Supabase自身で開発しているものもOSSとして公開している 【Supabase×React】サーバレスアプリ開発入門 51

    Slide 52

    Slide 52 text

    参考リンク 公式ドキュメント https://supabase.com/docs 開発者を魅了するオープンソースソフトウェア Supabase とは | AWS Dev Day 2022 Japan https://www.youtube.com/watch?v=XWYkpQRLsFk 【Supabase×React】サーバレスアプリ開発入門 52