これから流行りそうなSupabaseを触ってみた 

この記事は マイナビ [Advent Calendar 2021](https://qiita.com/advent-calendar/2021/mynavi) 23日目の記事となります。

Firebaseの代替になるのでは？と巷で話題のSupabaseを試してみました。
FirebaseはNoSQLでデータを扱うことに対して、SupabaseはデータベースにPostgreSQLを使用していると聞いて、興味が沸きましたので、今回触れてみたいと思います。

# Supabaseとは
「Firebase Alternative」を謳っており、オープンソースとして[公開されています](https://github.com/supabase/supabase)。
いわゆるBaaS(Backend As A Service)と呼ばれるサービスです。
2021年12月現在、提供されているサービスはDatabase、Authentication、Storageの3つとなっています。（近いうちにFunctionsが公開されそうです。）

https://supabase.io/

[各サービスの料金体系は公式サイトをご覧ください](https://supabase.com/pricing)

個人的には馴染みのあるSQLでデータを扱うことができるのは結構熱いなと思います。
NoSQLは少し癖があり、学習コストもそこそこ高いのがネックだったと思うので、RDBの選択肢が増えるのはバックエンドエンジニアにとっては朗報だと感じます。


# Work
今回は、公式が公開しているTODOリストアプリを動かしてみたいと思います。

https://github.com/supabase/supabase/tree/master/examples/react-todo-list-collaborative


また、実際に手を動かして実装を進めたい方向けに、[ハンズオン形式のチュートリアル](https://dev.to/awalias/howto-build-collaborative-realtime-task-lists-in-react-4k52)があります。

## アカウント作成

まずはアカウントを作成します。
現在はGitHubアカウントでのログインのみとなっております。
![FireShot Capture 003 - Supabase - app.supabase.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/e7faa248-aa61-59ca-4794-8fc445cd9414.png)


## プロジェクトを作成
ログインが完了後、イケてる管理画面が表示されますので、今回使用するサンプルのプロジェクトを作成したいと思います。

![FireShot Capture 005 - Supabase - Supabase - app.supabase.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/1f71956f-16f1-3fa7-7cc4-084554005326.png)


ボタンを押下後、以下のフォームが表示されます。

![FireShot Capture 006 - Supabase - app.supabase.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/0aaa6803-a8e6-2b0b-bd42-1614de0237ff.png)


プロジェクト作成後、APIキー、URLが確認できるようになります。
後ほど利用するので、メモしておきましょう。（管理画面からいつでも確認できます。）

![FireShot Capture 007 - API Settings - Supabase - app.supabase.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/4e61ab0e-7625-5e35-2b81-894cc227b52b.png)


##　データベースを作成
先にアプリで使用するテーブルを作成したいと思います。

サイドバーに表示されているSQL editorのアイコンをクリックし、以下のSQLを入力します。


[db/todo_list_schema.sql](https://github.com/supabase/supabase/blob/master/examples/react-todo-list-collaborative/db/todo_list_schema.sql)

```SQL
CREATE TABLE lists (
  uuid text,
  id bigserial PRIMARY KEY,
  inserted_at timestamp without time zone DEFAULT timezone('utc' :: text, now()) NOT NULL,
  updated_at timestamp without time zone DEFAULT timezone('utc' :: text, now()) NOT NULL
);

CREATE TABLE tasks (
  task_text text NOT NULL,
  complete boolean DEFAULT false,
  id bigserial PRIMARY KEY,
  list_id bigint REFERENCES lists NOT NULL,
  inserted_at timestamp without time zone DEFAULT timezone('utc' :: text, now()) NOT NULL,
  updated_at timestamp without time zone DEFAULT timezone('utc' :: text, now()) NOT NULL
);

alter publication supabase_realtime add table lists;
alter publication supabase_realtime add table tasks;
```

![FireShot Capture 010 - SQL - Supabase - app.supabase.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/1eaaa521-4e06-a361-6503-adf3e88f0f9c.png)

RUNボタンを押下後、テーブルが作成されていることが確認できます。

![FireShot Capture 012 - Supabase - app.supabase.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/143fe88e-c942-932d-ec35-febd1688ea6f.png)


## サンプルコードをclone
データベース作成後は、サンプルのコードをcloneします。

```
git clone https://github.com/supabase/supabase.git
```
## .envファイルを作成

まずは、サンプルコードが保存されている階層に移動します。

```
cd supabase/examples/react-todo-list-collaborative
```
移動した階層に`.env`ファイルを作成し、先程メモしたAPIキーとURLを入力し、保存します。

```
REACT_APP_SUPABASE_URL=<your-supabase-url>
REACT_APP_SUPABASE_KEY=<your-supabase-key>
```

## アプリを動かしてみる

サンプルのコードを動かす準備できましたので、実際に動かしてみます。
先程の階層で以下のコマンドを実行します。

```
npm install
npm start
```

その後、ブラウザで以下の画面が表示されます。

![FireShot Capture 013 - Supabase Task List - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/c0c383b5-0f9a-7ea1-dda9-798d95dd93f3.png)

`new task list`ボタンを押下後、TODOリスト画面が表示されます。

![FireShot Capture 014 - Supabase Task List - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/7e38b328-1dbd-94e1-d23a-8e024ed7e066.png)

`add task`ボタンでタスクを追加後、管理画面を確認すると、しっかりデータが登録されていました。

![FireShot Capture 015 - Supabase - app.supabase.io.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254954/c1b7feda-718a-1551-96c1-df24a679917c.png)

## コードを見てみる

サンプルコードでは、カスタムフックにSupabaseの呼び出し部分がまとめられています。

https://github.com/supabase/supabase/blob/master/examples/react-todo-list-collaborative/src/Store.js

以下、ソースからデータ操作部分を抜粋

```JavaScript
export const addTask = async (task_text, list_id) => {
  try {
    let { data, error } = await supabase.from('tasks').insert([{ task_text, list_id }])
    if (error) {
      throw new Error(error)
    }
    return data
  } catch (error) {
    console.log('error', error)
  }
}

export const updateTask = async (task_id, values) => {
  try {
    let { data, error } = await supabase.from('tasks').update(values).eq('id', task_id)
    if (error) {
      throw new Error(error)
    }
    return data
  } catch (error) {
    console.log('error', error)
  }
}

export const createList = async (uuid) => {
  try {
    let { data, error } = await supabase.from('lists').insert([{ uuid }])
    if (error) {
      throw new Error(error)
    }
    return data[0]
  } catch (error) {
    console.log('error', error)
  }
}

export const fetchList = async (list_uuid) => {
  try {
    let { data, error } = await supabase
      .from('lists')
      .select(`*, tasks(*)`)
      .eq('uuid', list_uuid)
      .single()
    if (error) {
      throw new Error(error)
    }
    return data
  } catch (error) {
    console.log('error', error)
  }
}
```

データの操作部分も`.from`や`.select`といった、馴染みのある単語を使用しているので分かりやすいですね！

# 感想
現在担当しているプロジェクトでFirebaseを使用しているのですが、正直NoSQLの作法に中々慣れず苦労していました。
SupabaseのようにRDBでデータを扱えると、学習コストも低く、設計もより簡単にできるだろうなと感じています。
まだベータ版ということもあり、本番での運用が難しいところではありますが、今後の発展がとても楽しみです。



# 参照

https://dev.classmethod.jp/articles/tried-using-supabase/

https://zenn.dev/iminux/articles/2b2a2bbab15330#%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%AB