# GraphQL Query の作成

GraphQL において、 データの取得・閲覧などの処理は Query と呼ばれる形で定義されます。

まずは、サンプルで投入した 5件のタスク一覧を表示する、 タスク一覧の GraphQL Query を作成してみましょう。

# Query の定義

Laravel Lighthouse での GraphQL 定義は、 graphql/schema.graphql に記述されます。

graphql/schema.graphql にはすでに、 user 等の記述があるため、 以下のような GraphQL 定義を、 ファイルの末尾に追記しましょう。

extend type Query {
    tasks: [Task!]! @all
}

type Task {
    id: ID!
    name: String!
    priority: Int!
    has_done: Boolean!
    created_at: DateTime!
    updated_at: DateTime!
}

Lighthouse で、Query の定義をする場合、 type Query 内にその定義を追加します。

今回は tasks という名前の Query を追加し、: の後ろで レスポンスの型 [Task!]! を定義しています。 [Task!]! は Task 型の配列を意味し ! は Null ではないことを表します。

レスポンスの型で利用した Task 型は、type Task{ ... } の記述で定義し、 それぞれ、データベースの列項目を記述しています。

GraphQL の定義が整ったら、altair で以下のようなクエリを入力して リクエストを送信することで、タスクの一覧を取得することが出来ます。

TIP

Query はすでにデフォルトで type Query の記述がなされているため、 extend キーワードを用いて定義を拡張しています。

query{
  tasks{
    name
  }
}

Lighthouse では、Eloquent クラスを App/Models 名前空間に展開することで、 型名と Eloquent クラスの自動マッピングが 行われます。

GraphQL 定義で利用した @all は 該当するEloquent からすべてのデータを取得する機能を持つため、 これを利用して、タスク一覧の Query を作成することが出来ます。

# レスポンスのカスタマイズ

altair で発行するクエリを以下のように変更することで、 レスポンスに、 priority を 含めることが可能になります。

query{
  tasks{
    name
    priority
  }
}

priority だけでなく、 id も created_at も、 lighthouse の側の type で定義した項目は全て、クライアント側から取得可能になります。

逆に、updated_at などを クライアント側に表示したくない場合は、 lighthouse 側での type 定義から、以下のようにして updated_at を削除します。

type Task {
    id: ID!
    name: String!
    priority: Int!
    has_done: Boolean!
    created_at: DateTime!
}

lighthouse の type 側で定義されていない項目は、 たとえ該当のデータベースにその列名があったとしても、 クライアント側でデータを取得することは出来ません。

updated_at を type の定義から削除したとき、 以下のようなクエリはエラーとなります。

query{
  tasks{
    name
    priority
    updated_at
  }
}

# Query 処理のカスタマイズ

@all のような、Lighthouse で提供されるディレクティブを利用すれば、 特別なコードを記述することなく、 Eloquent の機能を利用した Query 定義が可能になりますが、 実際のアプリケーション開発では、殆どの Query で何らかのロジックが必要になるでしょう。

Query の処理をコードベースで記述したい場合、 app/GraphQL/Queries フォルダを作成して、Query クラスを定義します。 app/GraphQL/Queries/Tasks.php を作成して以下のようなQuery クラスを作成してみましょう。

<?php
namespace App\GraphQL\Queries;

use App\Models\Task;

class Tasks
{
    public function __invoke($rootValue, array $args)
    {
        $tasks = Task::orderBy("priority","DESC")->get();

        return $tasks;
    }
}

Query クラスのクラス名は、 GraphQL 側で定義したクエリ名と一致させます。 ここでは tasks という名前で Query を定義しているため、クラス名は Tasks となります。

クエリの処理は、 クラスの __invoke 関数内で定義します。 上記のコードでは、単純に task テーブルの全件を取得するのではなく、 priority の列の値で、降順にソートした結果を返却するようコードを記述しています。

Query クラスの作成ができたら、 schema.graphql の記述から以下のようにして @allを削除します。

extend type Query {
    tasks: [Task!]!
}

最後に、 altair で 以下のようなクエリを発行して、優先度で降順にソートされた結果が確認できるでしょう。

query{
  tasks{
    name
    priority
  }
}

# Check!

次のステップに進む前に以下の内容をもう一度確認しておきましょう。

  • @all でQuery を定義して、 GraphQL からテーブルの内容を全件取得出来ますか?
  • 定義した Query を altair から発行する際に、項目名を選択して、レスポンスの内容を変化させることが出来ますか?
  • PHP で定義した Query クラスの内容で、レスポンスのソート順や項目の数等を変化させることが出来ますか?