コンテンツにスキップ

GraphQLスキーマは型から構成されています。このセクションではGraphQLのいろいろな型と、それをLighthouseで動作させるための定義方法について説明します。 GraphQLにおける型についての詳細はGraphQLドキュメントを参照してください。

オブジェクト型

オブジェクト型はAPIのリソースを定義するものでEloquentモデルと密接に関連しています。 オブジェクト型は一意な名前を持ち、1つ以上のフィールドを含む必要があります。

type User {
  id: ID!
  name: String!
  email: String!
  created_at: String!
  updated_at: String
}

type Query {
  users: [User!]!
  user(id: ID!): User
}

スカラ型

スカラ型はGraphQLスキーマの最も基本的な要素です。StringInt など、いくつかビルトインのスカラ型が存在します。

LighthouseはLaravelでうまく動作する、すぐに使えるスカラをいくつか提供しています。スカラについては、スカラに関するAPIリファレンス を参照してください。

独自のスカラ型を定義するには、php artisan lighthouse:scalar <Scalar name>を実行してスキーマに含めます。Lighthouseは設定可能なデフォルトの名前空間からスカラ型を探します。

scalar ZipCode

type User {
  zipCode: ZipCode
}

他にも、mll-lab/graphql-php-scalars で提供されているような、サードパーティ製のスカラを使うこともできます。 composer requireコマンドで、スキーマにスカラを追加してください。 追加したら@scalarディレクティブで、任意の完全修飾クラス名を指定します。

scalar Email @scalar(class: "MLL\\GraphQLScalars\\Email")

独自のスカラ型を実装する方法

列挙型

列挙型は制限された値のセットを持つ型です (Laravelのデータベースマイグレーションで使えるenumと似ています)。 UPPERCASEな文字列のキーのリストとして定義されます。

スキーマの定義

実際の値は@enum ディレクティブで定義できます。

enum EmploymentStatus {
  INTERN @enum(value: 0)
  EMPLOYEE @enum(value: 1)
  TERMINATED @enum(value: 2)
}

これで、スキーマの一部としてenumを使用できるようになります。

type Employee {
  id: ID!
  name: String
  status: EmploymentStatus!
}

type Query {
  employees: [Employee!]! @all
}

この例では、ベースになる値は実際には整数です。データベースからモデルを取得する際にマッピングが適用されて、これらの整数がEnumで定義した文字列キーに変換されます。

return [
  ['name' => 'Hans', 'status' => 0],
  ['name' => 'Pamela', 'status' => 1],
  ['name' => 'Gerhard', 'status' => 2],
];

GraphQLのクエリーは、マジックナンバーの代わりに意味のある名前を返します。

{
  employees {
    name
    status
  }
}
{
  "data": {
    "employees": [
      { "name": "Hans", "status": "INTERN" },
      { "name": "Pamela", "status": "EMPLOYEE" },
      { "name": "Gerhard", "status": "TERMINATED" }
    ]
  }
}

enumの内部値がフィールド名と同じ場合は、@enumを省略できます。

enum Role {
  ADMIN
}

上記の例で、フィールドADMINのPHP内部での値はstring('ADMIN')となります。

PHPのネイティブでの定義

PHPで作ったenumの定義はconstをGrahpQL側のスキーマ定義で再利用したい場合は、PHPのネイティブなenum型をTypeRegistryで登録することもできます。 方法は、単にEnumType を定義して、それを登録するだけです。

use GraphQL\Type\Definition\EnumType;
use Nuwave\Lighthouse\Schema\TypeRegistry;

$episodeEnum = new EnumType([
    'name' => 'Episode',
    'description' => 'スターウォーズ三部作',
    'values' => [
        'NEWHOPE' => [
            'value' => 4,
            'description' => '1977年にリリース.'
        ],
        'EMPIRE' => [
            'value' => 5,
            'description' => '1980年にリリース.'
        ],
        'JEDI' => [
            'value' => 6,
            'description' => '1983年にリリース.'
        ],
    ]
]);

// これはシングルトンなので、コンテナを通して解決します。
$typeRegistry = app(TypeRegistry::class);

$typeRegistry->register($episodeEnum);

BenSampo/laravel-enumを使用している場合は、Nuwave\Lighthouse\Schema\Types\LaravelEnumTypeを使用して、GraphQLのenum型を作成することができます。

例えば、以下のenumがあった場合:

<?php

namespace App\Enums;

use BenSampo\Enum\Enum;

final class UserType extends Enum
{
    public const Administrator = 0;
    public const Moderator = 1;
    public const Subscriber = 2;
    public const SuperAdministrator = 3;
}

以下の方法でServiceProviderに登録できます。元々のEnumクラスをLaravelEnumTypeでラップすることを忘れないでください。

<?php

namespace App\GraphQL;

use App\Enums\UserType;
use Illuminate\Support\ServiceProvider;
use Nuwave\Lighthouse\Schema\TypeRegistry;
use Nuwave\Lighthouse\Schema\Types\LaravelEnumType;

class GraphQLServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @param  \Nuwave\Lighthouse\Schema\TypeRegistry  $typeRegistry
     * @return void
     */
    public function boot(TypeRegistry $typeRegistry): void
    {
        $typeRegistry->register(
             new LaravelEnumType(UserType::class)
        );
    }
}

デフォルトで生成される型の名前は、LaravelEnumTypeで与えられたクラスと同じような形になります。

$enum = new LaravelEnumType(UserType::class);
echo $enum->name; // UserType

デフォルト値が適切でない場合や名前が衝突する時は、名前を上書きすることができます。

$enum = new LaravelEnumType(UserType::class, 'UserKind');
echo $enum->name; // UserKind

入力型

入力型はフィールド引数用の複雑なオブジェクトを記述するために使用できます。 見た目はオブジェクト型に似ていますが、振る舞いは異なるので注意してください。 入力型のフィールドは引数と同じように扱われます。

input CreateUserInput {
  name: String!
  email: String
}

type User {
  id: ID!
  name: String!
  email: String
}

type Mutation {
  createUser(input: CreateUserInput! @spread): User @create
}

インターフェース

GraphQLのinterfaceはPHPのインターフェースと似ています。 実装するすべての型が提供しなければならない共通のフィールドのセットを定義します。 Laravelのプロジェクトでインターフェイスを使用する一般的なユースケースは、データ型にポリモーフィックな関係がある時です。

Interface

interface Named {
  name: String!
}

オブジェクト型は、interfaceで指定されたフィールドをすべて用意することで、指定されたインターフェースを実装することができます。

type User implements Named {
  id: ID!
  name: String!
}

ですので、以下の定義は無効です。

type User implements Named {
  id: ID!
}

インターフェースは、特定のクエリから返される具象オブジェクトの型を決定する方法が必要となります。Lighthouseはデフォルトの型リゾルバを提供していて、これはリゾルバが返す値に対してclass_basename($value)を呼び出すことで動作します。

また、カスタムの型リゾルバを提供することもできます。カスタムインタフェースクラスを作成する場合はphp artisan lighthouse:interface <インターフェース名> を実行します。これは自動的にデフォルトのネームスペースに置かれ、Lighthouseによってディスカバリされます。

詳細はGraphQLのリファレンスgraphql-phpのドキュメントを参照してください。

ユニオン型

Unionは、他のオブジェクト型を列挙した抽象型です。 異なる型を返すことができるという点ではインターフェースと似ていますが、ユニオン型ではフィールドを定義できません。

union Person = User | Employee

type User {
  id: ID!
}

type Employee {
  employeeId: ID!
}

インターフェースと同様に、ユニオンの具体的なオブジェクト型を解決された値に基づいて決定する方法が必要です。デフォルトの型リゾルバがうまくいかない場合は、php artisan lighthouse:union <Union name>を使って独自の型を定義してください。 これは自動的にデフォルトのネームスペースに置かれ、Lighthouseによってディスカバリされます。

詳細は、GraphQLリファレンスgraphql-phpのドキュメント を参照してください。