Fluent API
プロンプトに「Fluent API」を含めることで、ClaudeCodeは直感的で読みやすいメソッドチェーンを生成できます。弊社では、長い引数リストを避けたい場合や、設定を段階的に構築したい場合にFluent APIパターンを使用します。
弊社の推奨ルール
- thisを必ず返す - メソッドチェーンを可能にする
- イミュータブルにする - 各操作で新しいインスタンスを生成
- 自然言語に近い命名 - メソッド名は動詞で統一
- ビルダーでは終端メソッドを明確にする - build()やexecute()で処理を確定
- 型安全性を保つ - チェーン中でも型情報を維持
ClaudeCodeでの利用
クエリビルダー実装
複数の条件を直感的にチェーンして構築したい場合
「Fluent APIでクエリビルダーを作って。where、orderBy、limitをチェーンできるように」
既存コードの改善
手続き的なコードを読みやすいメソッドチェーンに変換
「このクラスにFluent APIを実装」
設定オブジェクト構築
複雑な設定を段階的に組み立てて可読性を向上させる
「設定オブジェクトをFluent APIで構築できるように」
長い引数リストではなくFluent APIを使う
弊社では、4つ以上の引数がある場合や、設定が段階的に構築される場合にFluent APIを使用します。理由は可読性と保守性の向上です。
// ❌ 推奨しない:複数の関数呼び出し
const user = createUser();
setName(user, 'Alice');
setAge(user, 25);
setEmail(user, 'alice@example.com');
activate(user);
従来の手続き型アプローチでは、複数の関数を順番に呼び出す必要があり、可読性が低下します。Fluent APIでは自然言語のような流れでコードを書けます。
// ✅ 推奨:Fluent API
class User {
constructor(
private readonly name: string = '',
private readonly age: number = 0,
private readonly email: string = '',
private readonly isActive: boolean = false
) {
Object.freeze(this);
}
withName(name: string): User {
return new User(name, this.age, this.email, this.isActive);
}
withAge(age: number): User {
return new User(this.name, age, this.email, this.isActive);
}
withEmail(email: string): User {
return new User(this.name, this.age, email, this.isActive);
}
activate(): User {
return new User(this.name, this.age, this.email, true);
}
各withメソッドが新しいインスタンスを返すことで、イミュータブルなオブジェクトを維持しながらメソッドチェーンを可能にします。
get profile() {
return {
name: this.name,
age: this.age,
email: this.email,
active: this.isActive
};
}
}
// 使用例:自然で読みやすい
const user = new User()
.withName('Alice')
.withAge(25)
.withEmail('alice@example.com')
.activate();
console.log(user.profile);
個別のセッターメソッドではなくFluent APIを使う
弊社では、HTTPクライアントのような設定が多いAPIでは、個別のセッターではなくFluent APIを採用します。統一性と使いやすさを重視するためです。
class HttpRequest {
constructor(
private readonly url: string,
private readonly method: string = 'GET',
private readonly headers: Record<string, string> = {},
private readonly params: Record<string, string> = {},
private readonly body?: any
) {
Object.freeze(this);
}
HTTPリクエストの設定を段階的に構築するFluent APIです。各メソッドが新しいリクエストオブジェクトを返し、設定を積み重ねていきます。
header(key: string, value: string): HttpRequest {
return new HttpRequest(
this.url,
this.method,
{ ...this.headers, [key]: value },
this.params,
this.body
);
}
param(key: string, value: string): HttpRequest {
return new HttpRequest(
this.url,
this.method,
this.headers,
{ ...this.params, [key]: value },
this.body
);
}
json(data: any): HttpRequest {
return new HttpRequest(
this.url,
'POST',
{ ...this.headers, 'Content-Type': 'application/json' },
this.params,
JSON.stringify(data)
);
}
executeメソッドは終端メソッドとして、実際のHTTPリクエストを実行します。設定の構築フェーズと実行フェーズを明確に分離します。
async execute(): Promise<Response> {
const url = new URL(this.url);
for (const [key, value] of Object.entries(this.params)) {
url.searchParams.set(key, value);
}
return fetch(url.toString(), {
method: this.method,
headers: this.headers,
body: this.body
});
}
}
// ファクトリー関数
function http(url: string): HttpRequest {
return new HttpRequest(url);
}
実用例では、ファクトリー関数とメソッドチェーンを組み合わせて、直感的で読みやすいAPIを提供します。設定の内容が一目で分かります。
// 使用例
const response = await http('https://api.example.com/users')
.header('Authorization', 'Bearer token')
.param('page', '1')
.param('limit', '10')
.execute();
const createResponse = await http('https://api.example.com/users')
.header('Authorization', 'Bearer token')
.json({ name: 'John', email: 'john@example.com' })
.execute();
よくある問題
Fluent APIでのthis消失
メソッドチェーンでthisが返されずチェーンが切れる問題です。必ずthisまたは新しいインスタンスを返すように実装します。
// ❌ エラー:thisが消える
class Builder {
private value = 0;
setValue(val: number) {
this.value = val;
// return thisを忘れる
}
build() {
return this.value;
}
}
// const result = new Builder().setValue(10).build(); // エラー
// ✅ 解決:必ずthisを返す
class Builder {
private value = 0;
setValue(val: number): this {
this.value = val;
return this; // 必須
}
build(): number {
return this.value;
}
}
// チェーンが正常に動作
const result = new Builder().setValue(10).build();
Q: イミュータブルにする必要がある?
A: 弊社では推奨。副作用を防ぎ、デバッグしやすくなる。パフォーマンスが問題なら可変版も検討。
Q: すべてのメソッドがFluent APIである必要は?
A: 設定系や条件系のメソッドのみ。計算結果を返すメソッドは通常の戻り値で良い。
Q: 終端メソッドの命名規則は?
A: ビルダーパターンでは build()、execute()、toXxx()など。通常のFluent APIでは不要。