バックエンド開発が捗るほど、フロントが辛くなる怪奇現象
皆さん、バックエンドでAPIをガシガシ作り続けているとき、ふとフロントエンド側のコードを見て絶望したことはありませんか?
「APIが1つ増えた...。またフロントでfetch関数(フェッチズ!)を書いて、レスポンスの型を定義して、エラーハンドリングして...」
「えっ、バックエンド側でフィールド名変わったの?フロントの修正箇所どこだっけ...(全検索開始)」
APIが増えれば増えるほど、フロントエンドの実装はこんな感じの「コピペと手作業の迷宮」になりがちです。
実際のディレクトリ(仮想)の惨状
例えば、こんな風にエンドポイントが増えていくと...
frontend/app/api/
├── estimates.ts <-- 似たような fetch('/api/estimates') が並ぶ
├── categories.ts <-- 似たような fetch('/api/categories') が並ぶ
├── dashboard.ts <-- 延々と続くコピペ
└── types.ts <-- バックエンドの型を必死に手書きで写したもの
正直、「バックエンドの仕様(OpenAPI)があるんだから、フロントの通信コードも勝手に生まれてきてくれよ!」って思いますよね?
それを本当に叶えてくれるのが、今回紹介する Orval(オーバル) です。
魔法の正体:Orval(オーバル)とは?
一言で言うと、「OpenAPI(openapi.json)を読み込んで、フロントエンドの通信ロジックを全自動生成する」ツールです。
これを使うと、私たちが手書きしていた「fetch」や「React Queryのカスタムフック」が、コマンド一発で爆誕します。
ここが神
- 書き写し作業ゼロ: バックエンドの型をフロントに手書きで写す必要がなくなります。
- 仕様変更に強い: バックエンド側で型が変わっても、再生成すれば即座にTypeScriptがエラーで教えてくれます。
- React Queryと相性抜群: 単なる関数だけでなく、useQuery などのHookまでセットで作ってくれます。
爆速導入手順
1. 【バックエンド】仕様書を「勝手に」出力させる
「Orvalを使うために、あの複雑なJSONを手書きしなきゃいけないの?」
いいえ、その必要はありません。FastAPI などのモダンなフレームワークなら、普通にAPIのコードを書くだけで仕様書が手に入ります。
# backend/main.py
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Estimate(BaseModel):
id: int
project_name: str
@app.get("/api/estimates")
def get_estimates() -> list[Estimate]:
return [{"id": 1, "project_name": "キッチンリフォーム"}]
これだけでOK。たとえ Dockerコンテナの中 で動かしていても、FastAPIを起動して http://localhost:8000/openapi.json にアクセスすれば、Orvalが食べるための「API設計図」がすでに自動生成されています。
2. 【フロントエンド】Orvalをインストール
フロント側でOrvalと、実際に通信を担当するライブラリを入れます。
yarn add -D orval
yarn add ky @tanstack/react-query
3. 設定ファイルを作成 (orval.config.ts)
バックエンド(コンテナ等)から「漏れ出してきた」JSONをどこから読み込むか指定します。
export default {
projectApi: {
// 起動中のバックエンドURL、または保存したファイルを指定
input: 'http://localhost:8000/openapi.json',
output: {
mode: 'tags-split',
target: 'app/gen',
client: 'react-query', // React Query用フックも自動生成
override: {
mutator: {
path: './app/api/mutator/ky.ts', // 通信の共通マナー
name: 'kyInstance',
},
},
},
},
};
4. 通信の共通ルールを作成 (app/api/mutator/ky.ts)
Orvalが実際にリクエストを投げるときに使う、共通の窓口を1つだけ手書きします。
import ky from 'ky';
export const kyInstance = <T>(config: any): Promise<T> => {
return ky(config.url, {
method: config.method,
json: config.data,
searchParams: config.params,
}).json();
};
5. 魔法の呪文を唱える
ターミナルで叩きます。
yarn orval
これだけで、app/gen の中に大量の fetch関数(フェッチズ!) と 型定義 が自動で出来上がります!
まとめ:エンジニアは「UI」に集中しよう
Orvalを導入してから、私の開発スタイルは激変しました。
- Before: 仕様書を読み、型を写し、fetchを書き、スペルミスでバグらせる苦行。
- After: yarn orval して、生成されたHookをコンポーネントで呼び出すだけ。
「fetch(フェッチズ!)を自動生成する」という体験は、一度味わうともう手書きには戻れません。
API量産期に疲弊している皆さんは、ぜひ今すぐこの魔法をコンテナの中から引っこ抜いてみてください!