自分と同じ身長と体重のポケモンを検索できる診断サービス「PokeFit(ポケフィット)」を作りました
WBCで大谷翔平選手の身長と体重がガブリアスと同じということが話題になったのをみて、思いつきで作ってみました。
ぜひ皆さん使ってみてください!
ちなみに私はプテラでした。
以下技術的な話になります。
技術スタック
- 言語
- TypeScript
- フレームワーク
- Next.js
- バックエンド
- Supabase
- ホスティング
- Vercel
言語・フレームワーク・ホスティングについては後述のvercel/ogを軸に選定しています。
ポケモンのデータ(図鑑No・名前・高さ・重さ)はPokeAPI、イラストは転寝みるくさんのものを許可をいただいて使用しています。
PokeAPIでも各ポケモンのイラストは取得可能です。
Supabaseについて
DBとストレージを1サービスで完結できてかつ無料(DB:500MB、ストレージ:1GB)という点がポイントで選びました。
初めて使用したのですが一言でいうと優しいです。
環境構築が簡単、本当に
DockerとSupabaseコマンドがあればすぐさまローカル環境を構築できます。
supabase login
supabase init
supabase start
import { createClient } from '@supabase/supabase-js'
import { Database } from 'lib/database.types'
const supabase = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
)
const { data, error } = await supabase
.from('countries')
.select()
この手軽さは今まで私が使用したことのあるBaaSの中ではダントツです。
またマイグレーションをGitHub Actionsに乗せるのも簡単です。
name: Deploy
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }}
SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }}
steps:
- uses: actions/checkout@v3
- uses: supabase/setup-cli@v1
with:
version: latest
- run: supabase link --project-ref $SUPABASE_PROJECT_ID
- run: supabase db push --debug
コンソールとドキュメントのサポートが充実
コンソールではテンプレートが用意されており、初学者でも手軽にSQLやセキュリティーポリシーを作成できます。
またドキュメントでは、SQL・JavaScript・Dartそれぞれでサンプルコードが記載されています。
Supabase is an open source Firebase alternative.
と言っているだけあって、バックエンドの知見がない方々へのサポートはかなり意識してやっているなと感じました。
注意点
内部ではPostgRESTを使用しているため、そちらで対応していないPostgreSQL関数はクライアントライブラリから直接使用できません。
カスタム関数を作成する必要があります。
create or replace function get_planets()
returns setof planets
language sql
as $$
select * from planets;
$$;
const { data, error } = supabase.rpc('get_planets').eq('id', 1)
参照:Supabase Database Functions
今回はDatabaseとStorageのみしか使用していませんが、認証やEdge Functionsも提供しているのでまた今度使ってみようと思います。
画像メーカー開発の鬼門、SNSへの共有方法の解決策「vercel/og」
画像メーカーを作った際にはユーザーの方に作成した画像をTwitterに共有していただきたいのですが、Twitterのアカウント連携なしで画像ツイートはできません。
方法としては以下2つになるのですがどちらもユーザーにとって不便です。
- Twitterのアカウント連携をして画像ツイートできるようにする
- 画像メーカーを使うためだけにアカウント連携したくない
- 画像を手動で保存してツイートしてもらう
- 手間がかかる
そこでOGPの出番です。
URLを共有してOGP画像を表示させることで、間接的に画像をSNSに共有できるようにします。
今までの課題として画像が生成される度にストレージに保存する必要があるため、サービスの維持費、またそれを踏まえてどう実装するかがネックになっていました。
それを解決したのがvercel/ogです(画像メーカーのために作られたものではないですが)。
vercel/ogは、Vercel Edge Functionsを使用して「エッジ上で動的に」OGP画像を生成できるライブラリです。
以下公式から抜粋したサンプルコードです。
画像自体を返すAPIを実装してそのパスをメタタグに指定してあげるだけで完了です。
pages/api/og.tsx
import { ImageResponse } from '@vercel/og';
export const config = {
runtime: 'edge',
};
export default function () {
return new ImageResponse(
(
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
}}
>
Hello world!
</div>
),
{
width: 1200,
height: 600,
},
);
}
使用できるCSSには制限があります。
index.js
<head>
<title>Hello world</title>
<meta
property="og:image"
content="https://<your domain>/api/og"
/>
</head>
もちろんクエリパラメータを指定できるので、固定の画像にテキストを埋め込むような画像メーカーであればVercelのみで無料で作れてしまいます。
例
https://<your domain>/api/og?message=布団が吹っ飛んだ
HobbyプランではVercel Edge Functionsは月500,000回までです。また商用利用ができない点もご注意ください。
参照:Find a plan to power your projects
共有するSNSが1個、かつ共有先のSNSがクロールした後に画像をキャッシュしてくれる前提で考えると、単純計算で月250,000枚までは無料で画像を生成できることになります。
生成された画像をサービス内に表示する分とSNSのクロール分で、画像1枚あたり2回Vercel Edge Functionsが実行される想定です。
おわりに
今回TypeScript以外はほぼ初めての技術スタックでしたが、ChatGPTのサポートのおかげでかなり早く作れました。
(もちろん便利なサービスやライブラリによる影響も大きいです)
ChatGPTの登場でアウトプットの速度が上がったのは喜ばしいことですが、その分体力(集中力?)は今まで以上に使うなと感じました。
今まで時間をかけてだらだらやっていたところが、短時間に圧縮されたと考えれば当然ですが。
アウトプットの速度に体がついていけるように筋トレした方がいいなと思いました。
今年中にプテラからザルードを目指します。
Discussion