この記事は Siv3D Advent Calender 2025 シリーズ1 15日目の記事です.
はじめに
みなさんどうも,緑獺おがめです.
緑獺は「みどりかわ」と読みます.
普段は C++ をメインに,Web 周りもちょくちょく触っています.
今回は Web 開発でよく聞く Supabase を Siv3D でも扱ってみようという記事になります.
Supabase とは
この記事を読んでいる人は Siv3D ないしは C++ をやっている方が多いと思いますので,Supabase についてお話をします.
Supabase とは,PostgreSQL をベースにしたオープンソースな開発プラットフォームです.
データベース処理を中心に機能が提供されており,オブジェクトストレージや認証なんかも機能として実装されています.
また,CLI や Dashboard も使い勝手がよく,個人的に最強だと思っています.
アプデが頻繁なのも良いところですね.
SDK
Supabase を扱うための SDK が用意されています.
公式サポート
- JavaScript (TypeScript)
- Flutter
- Swift
- Python
コミュニティサポート
- C#
- Go
- Java
- Kotlin
- Ruby
- Rust
- Godot Engine
しかし残念ながら,C++ は存在しません.
SDK を使わずとも
Supabase はRestAPIも一緒に立ててくれます.
これにより,SDK がなくとも Supabase を扱えます.
とても便利ですね.
今回は HTTP 通信を用いて Siv3D から Supabase を扱ってみたいと思います.
事前準備
Siv3D は v0.6.15 です.
開発用の Supabase を立てる
適当なディレクトリにて以下のコマンドを入力し,Supabase CLI にて開発用のローカル環境を立ち上げます.
Docker Container が沢山立ち上がります.
npx supabase init
npx supabase start
その後,以下のような出力が得られます.
╭──────────────────────────────────────╮
│ 🔧 Development Tools │
├─────────┬────────────────────────────┤
│ Studio │ http://127.0.0.1:54323 │
│ Mailpit │ http://127.0.0.1:54324 │
│ MCP │ http://127.0.0.1:54321/mcp │
╰─────────┴────────────────────────────╯
╭──────────────────────────────────────────────────────╮
│ 🌐 APIs │
├────────────────┬─────────────────────────────────────┤
│ Project URL │ http://127.0.0.1:54321 │
│ REST │ http://127.0.0.1:54321/rest/v1 │
│ GraphQL │ http://127.0.0.1:54321/graphql/v1 │
│ Edge Functions │ http://127.0.0.1:54321/functions/v1 │
╰────────────────┴─────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────╮
│ ⛁ Database │
├─────┬─────────────────────────────────────────────────────────┤
│ URL │ postgresql://postgres:postgres@127.0.0.1:54322/postgres │
╰─────┴─────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────╮
│ 🔑 Authentication Keys │
├─────────────┬────────────────────────────────────────────────┤
│ Publishable │ sb_publishable_abcdefghijklmnopqrstuv_abcdefgh │
│ Secret │ sb_secret_abcdefghijklm-abcdefgh_abcdefgh │
╰─────────────┴────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────╮
│ 📦 Storage (S3) │
├────────────┬──────────────────────────────────────────────────────────────────┤
│ URL │ http://127.0.0.1:54321/storage/v1/s3 │
│ Access Key │ 0123456789abcdefghijklmnopqrstuv │
│ Secret Key │ 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZab │
│ Region │ local │
╰────────────┴──────────────────────────────────────────────────────────────────╯
Studio という部分に注目し,このリンクにアクセスしてみます.
すると,Supabase Studio がブラウザで立ち上がり,リッチなダッシュボードから色々いじれます.
テスト用データの挿入
そこからまずは Table Editor を開き,テスト用のデータを入れていきます.
New Table から新規テーブルを作成します.
今回はworksテーブルを作成しました.
作成後は以下のような画面になります.
ついでに,適当なデータを挿入し,RLS を設定しておきます.
RLS (Row Level Security) に関しては,今回は割愛します.
次に認証に用いるユーザーデータを作ります.
Authentication からユーザーを追加します.
適当にhoge@example.com, パスワードはhogeで作りました.
Siv3D での記述
認証
いよいよ Siv3D でアクセスしていきます.
まずは認証してみます.
以下のコードを用意しました.
#include <Siv3D.hpp>
void Main()
{
const URL baseUrl = U"http://127.0.0.1:54321";
const String anonKey = U"sb_publishable_abcdefghijklmnopqrstuv_abcdefgh";
const HashTable<String, String> headers = {
{ U"Content-Type", U"application/json" },
{ U"apikey", anonKey }
};
const std::string data = JSON
{
{ U"email", U"hoge@example.com" },
{ U"password", U"hoge" },
}.formatUTF8();
URL authUrl = baseUrl + U"/auth/v1/token?grant_type=password";
AsyncHTTPTask task = SimpleHTTP::PostAsync(authUrl, headers, data.data(), data.size());
while (not task.isReady()) { System::Sleep(1ms); }
JSON json = task.getAsJSON();
Console << json.format();
while (System::Update()) {
}
}
URL で auth の password 認証を指定し,Request Body に認証情報を入れて Post することで認証が行えます.
実行結果は以下のようになり,きちんと認証できたことが分かります.
(access_tokenは認証ごとに異なるのでそのまま載せています.)
認証完了後はこのアクセストークンを利用してデータベースやオブジェクトストレージにアクセスします.
データベース
次はデータベースにアクセスしてみましょう.先ほどのアクセストークンを再利用します.
#include <Siv3D.hpp>
void Main()
{
const URL baseUrl = U"http://127.0.0.1:54321";
const String anonKey = U"sb_publishable_abcdefghijklmnopqrstuv_abcdefgh";
String accessToken;
{
const HashTable<String, String> headers = {
{ U"Content-Type", U"application/json" },
{ U"apikey", anonKey }
};
const std::string data = JSON
{
{ U"email", U"hoge@example.com" },
{ U"password", U"hoge" },
}.formatUTF8();
URL authUrl = baseUrl + U"/auth/v1/token?grant_type=password";
AsyncHTTPTask task = SimpleHTTP::PostAsync(authUrl, headers, data.data(), data.size());
while (not task.isReady()) { System::Sleep(1ms); }
JSON json = task.getAsJSON();
accessToken = json[U"access_token"].getString();
}
{
const HashTable<String, String> headers = {
{ U"Authorization", U"Bearer {}"_fmt(accessToken) },
{ U"apikey", anonKey }
};
URL restUrl = baseUrl + U"/rest/v1/works";
AsyncHTTPTask task = SimpleHTTP::GetAsync(restUrl, headers);
while (not task.isReady()) { System::Sleep(1ms); }
JSON json = task.getAsJSON();
Console << json.format();
}
while (System::Update()) {
}
}
認証時に取得したaccess_tokenをリクエストヘッダに含め,GET リクエストを送ることでデータを得られます.
今回はworksテーブルから取得してみました.
オブジェクトストレージ
最後に,見た目としても映える,オブジェクトストレージからの画像の取得をしてみます.
バケット名はimagesとし,その中からusers/ogame/icon.jpgを取得してみます.
データベースのテーブルと同様に,こちらにも適した Policy をつけておきます.
以下のコードを用意してみました.
#include <Siv3D.hpp>
void Main()
{
const URL baseUrl = U"http://127.0.0.1:54321";
const String anonKey = U"sb_publishable_abcdefghijklmnopqrstuv_abcdefgh";
String accessToken;
{
const HashTable<String, String> headers = {
{ U"Content-Type", U"application/json" },
{ U"apikey", anonKey }
};
const std::string data = JSON
{
{ U"email", U"hoge@example.com" },
{ U"password", U"hoge" },
}.formatUTF8();
URL authUrl = baseUrl + U"/auth/v1/token?grant_type=password";
AsyncHTTPTask task = SimpleHTTP::PostAsync(authUrl, headers, data.data(), data.size());
while (not task.isReady()) { System::Sleep(1ms); }
JSON json = task.getAsJSON();
accessToken = json[U"access_token"].getString();
}
Texture texture;
const FilePath saveFilePath = U"icon.jpg";
const HashTable<String, String> headers = {
{ U"Authorization", U"Bearer {}"_fmt(accessToken) },
{ U"apikey", anonKey }
};
URL storageUrl = baseUrl + U"/storage/v1/object/images/users/ogame/icon.jpg";
AsyncHTTPTask task = SimpleHTTP::GetAsync(storageUrl, headers, saveFilePath);
while (System::Update()) {
if (task.isReady()) {
if (task.getResponse().isOK()) {
texture = Texture{ saveFilePath };
}
else {
Print << U"Failed";
}
}
if (task.isDownloading())
{
Circle{ 400, 300, 50 }.drawArc((Scene::Time() * 120_deg), 300_deg, 4, 4);
}
if (texture)
{
texture.drawAt(Scene::CenterF());
}
}
}
Siv3D チュートリアル 62章のコードを参考にしています.
これを実行してみると……
無事,Supabase 上のオブジェクトストレージからデータの取得が行えました!!
あとがき
今回は,Web 開発でよく用いられる Supabase へ Siv3Dからアクセスしてみました.
Supabase は非常に高機能で,他にもデータベースの行の変更を検知してリアルタイムに通知をしてくれるような機能もあります.
もしよければ,みなさんも使ってみてください.
明日は たすくんさん( @23tas9 )の記事になります.お楽しみに!




