【ITニュース解説】Laravel Doesn’t Need GraphQL Part 2: Use Components with Props for Exact Data
2025年10月02日に「Dev.to」が公開したITニュース「Laravel Doesn’t Need GraphQL Part 2: Use Components with Props for Exact Data」について初心者にもわかりやすく解説しています。
ITニュース概要
Laravelでは、GraphQLを使わずとも必要なデータだけを効率的に取得できる。Bladeコンポーネントのプロパティをデータ定義として活用することで、APIでもBladeビューでも厳密に指定したデータのみを抽出し、利用可能だ。これにより、複雑な仕組みを追加せずLaravel内で開発が完結し、データ取得の最適化と開発のシンプル化を実現する。
ITニュース解説
Webアプリケーション開発では、フロントエンドが必要とするデータをバックエンドから効率的に取得することが重要になる。一般的に、GraphQLはフロントエンドがデータの種類や形を細かく指定できるため注目を集めている。これは、フロントエンドが特定のデータフィールドをリクエストし、GraphQLの層を通してバックエンドに問い合わせることで、要求したフィールドだけを正確に受け取れるという柔軟性を提供する。しかし、その柔軟性の代償として、開発者はGraphQLのスキーマ定義、ルール、規約といった新しい概念を学習する必要があり、既存のLaravelベースのバックエンドにGraphQLのレイヤーが加わることで、システム全体の複雑さが増すという課題も存在する。
この課題に対し、Laravelの標準機能であるBladeコンポーネントを拡張することで、GraphQLが提供する「必要なデータだけを正確に取得する」という利点を、Laravelの既存のワークフローを維持したまま実現するという新しいアプローチが提案されている。このアイデアの核は、Bladeコンポーネントを、単なるビューの部品としてだけでなく、データ転送オブジェクト(DTO)のようにデータを構造化し、公開する「データ契約」として活用することにある。
具体的には、コンポーネントのプロパティを、そのコンポーネントが外部に公開するデータフィールドとして扱う。これにより、個別のAPIやBladeの部分ビューごとに専用のDTOクラスを作成する代わりに、コンポーネント自体がどのモデルプロパティがそのコンテキストで許可されるかを宣言する役割を担うことができる。APIを構築する際には、Bladeビューを返すのと同様にコンポーネントを返すことで、そのコンポーネントのプロパティがAPIのデータ契約を明確に定義する。このように、コンポーネントはBladeレンダリングのためのビューとして機能すると同時に、APIレンダリングのための構造化されたレスポンスとしても機能し、新しいレイヤーを追加することなくDTOの役割を自然に代替することになる。
この仕組みを実現するためには、主に二つの「トレイト」と呼ばれるLaravelの共通機能を定義する必要がある。トレイトとは、複数のクラスで共通のメソッドやプロパティを再利用するための仕組みである。
一つ目はResponsableComponentトレイトである。このトレイトは、HTTPリクエストがJSON形式のレスポンスを要求しているか、それともHTML形式のレスポンスを要求しているかを判断し、それに応じて適切な形式のレスポンスを返す役割を担う。もしリクエストがJSONを求めている場合は、コンポーネントのデータをJSON形式で返し、そうでなければコンポーネントのHTMLビューをレンダリングして返す。これにより、同じコンポーネントがAPIのJSONレスポンスとしても、BladeのHTMLビューとしても機能できるようになる。
二つ目はArraySerializableComponentトレイトである。このトレイトは、コンポーネント内に定義されたすべての公開プロパティを自動的に配列に変換するtoArray()という静的メソッドを提供する。このメソッドは、コンポーネントのプロパティ名を収集し、Laravelの内部的なプロパティなどを除外して、純粋なデータプロパティのリストを配列として返す。この機能が、後述するデータベースクエリで必要なカラムだけを選択するために非常に重要となる。
これらのトレイトを実際に利用するには、新しいBladeコンポーネントを作成する際に、use ResponsableComponent, ArraySerializableComponent; のように記述して、作成したトレイトをコンポーネントに取り込む。これにより、そのコンポーネントはデータ契約の定義と柔軟なレスポンスの機能を持つことができる。毎回手動でトレイトをインポートする手間を省くためには、Laravelのphp artisan make:componentコマンドで新しいコンポーネントを作成する際のひな形(スタブ)をカスタマイズする方法がある。具体的には、php artisan stub:publish --tag=component.stubコマンドでスタブファイルを公開し、そのスタブファイルに上記二つのトレイトのuse文をあらかじめ記述しておくことで、以降作成されるすべてのコンポーネントに自動的にこれらのトレイトが組み込まれるようになる。
セットアップが完了したら、次は実際にデータを定義し、利用する段階に進む。まず、コンポーネントのプロパティとして、公開したいデータフィールドを宣言する。例えば、ユーザーの情報を表示するUserCardコンポーネントであれば、public string $name;やpublic string $email;のように、公開したいユーザーの氏名とメールアドレスのプロパティを定義する。これらのプロパティは、コンポーネントのコンストラクタでも初期化される。これにより、コンポーネント自体が「このコンポーネントはnameとemailというデータを持つ」という契約を明確に定義する。
次に、このコンポーネントをデータベースクエリに利用する。User::select(UserCard::toArray())->get();のように記述することで、ArraySerializableComponentトレイトが提供するtoArray()メソッドが呼び出される。このメソッドは、UserCardコンポーネントで宣言された公開プロパティ(この例ではnameとemail)のリストを配列として返し、User::select()メソッドはその配列を受け取って、データベースからnameとemailのカラムだけを厳密に取得する。これにより、たとえUserモデルが20個のカラムを持っていたとしても、本当に必要なnameとemailのカラムだけがフェッチされ、データの「オーバーフェッチ」(必要以上のデータを取得してしまうこと)を防ぐことができる。これはGraphQLが提供する「必要なデータだけを正確に取得する」というメリットを、LaravelのEloquentを使った一行のコードで実現していることに他ならない。
このアプローチはレスポンスの形式においても柔軟性を提供する。GraphQLは通常、JSON形式でしか応答しないが、このコンポーネントを使った方法では、APIエンドポイントからのリクエストに対してはJSONを返し、Webページからのリクエストに対してはHTMLフラグメントを直接返すことができる。例えば、return response()->json($users);とすればJSONレスポンスとして、return view('user.index', ['users' => $users]);とすればHTMLビューとしてデータを扱うことができる。フロントエンドでは、JSONを解析する手間なく、バックエンドから返されたHTMLをそのままDOMに挿入するだけで表示が可能になるため、開発の効率化にもつながる。
このLaravelコンポーネントを活用したデータ公開のアプローチは、GraphQLと比較して多くの利点がある。まず、GraphQLのスキーマ、リゾルバー、専用のGraphQLサーバーといった余分なレイヤーを追加する必要がないため、システムの複雑さを低減できる。また、開発者はLaravelのコントローラー、Eloquent、Bladeといった使い慣れたワークフローをそのまま利用できるため、新しい学習コストが少ない。コンポーネントのプロパティがデータ契約を厳格に定義するため、何が選択されるべきかが明確になり、データの整合性を保ちやすい。さらに、一つのコンポーネントがJSONのためのDTOとしても、HTMLのためのBladeビューとしても機能する「二重目的」を果たす。そして何よりも、この方法がLaravelネイティブであるため、Laravel開発者にとっては非常に親しみやすく、新しい言語やフレームワークの習得が不要である。
ただし、このアプローチにはいくつかの注意点も存在する。コンポーネントをデータ契約として利用する方法は、DTOのようにシンプルで厳格なプロパティを持つことを意図している。もし動的に計算されるフィールドや、特定の条件に基づいて表示が変わるプロパティが必要な場合でも、従来のコンポーネントと同じ方法で内部的に処理することができる。パフォーマンスに関して過度に心配する必要はない。ページに多くのコンポーネントがある場合でも、各データベースクエリが必要なカラムだけを厳密に取得するため、データベースへの負担はむしろ軽減される。これは最適化された状態であると言える。また、このアプローチは新規で開発するアプリケーションで最も効果を発揮する。既存のレガシーアプリケーションに導入する場合でも、部分的に採用していくことは可能だが、一晩で全てを置き換えることは現実的ではない。
結論として、GraphQLとは異なり、このLaravelコンポーネントをデータ契約として利用するアプローチは、APIとBladeビューの両方で機能する。JSON形式でデータを送信する場合でも、HTML形式でビューをレンダリングする場合でも、同じコンポーネントが「必要なデータだけを取得する」ことを保証し、データ転送の効率化と開発のシンプル化を実現する。