💹

【GraphQL】自分オリジナルのディレクティブを定義して使ってみる【Laravel・Lighthouse】

2023/07/09に公開

今回作るもの

idの値に100を足したフィールドを作成するディレクティブ

ファイル作成

今回作成するカスタムディレクティブの名前はidPlus100とします。
laravelでお馴染み、artisanコマンドで作成。

php artisan lighthouse:directive --field idPlus100

その後に、どのインターフェースをもとに作成するか聞かれるので、今回は[0]で作成する。

Which interfaces should the directive implement?:
  [0] Nuwave\Lighthouse\Support\Contracts\FieldResolver
  [1] Nuwave\Lighthouse\Support\Contracts\FieldMiddleware
  [2] Nuwave\Lighthouse\Support\Contracts\FieldManipulator

ディレクティブ実装

idPlus100Directive.php
<?php

namespace App\GraphQL\Directives;

use App\Models\Post;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;

final class IdPlus100Directive extends BaseDirective implements FieldResolver
{
    // TODO implement the directive https://lighthouse-php.com/master/custom-directives/getting-started.html

    public static function definition(): string
    {
        return /** @lang GraphQL */ <<<'GRAPHQL'
directive @idPlus100 on FIELD_DEFINITION
GRAPHQL;
    }

    /**
     * Set a field resolver on the FieldValue.
     *
     * This must call $fieldValue->setResolver() before returning
     * the FieldValue.
     *
     * @param  \Nuwave\Lighthouse\Schema\Values\FieldValue  $fieldValue
     * @return \Nuwave\Lighthouse\Schema\Values\FieldValue
     */
    public function resolveField(FieldValue $fieldValue)
    {
        $fieldValue->setResolver(function(Post $post, array $args, $context, $info) {
            return $post->idPlus100 = $post->id + 100;
        });
        return $fieldValue;
    }
}

作成したディレクティブを使う

type Post {
    id: ID!
    is_favorite: Int!
    content: String!
    idPlus100: Int! @idPlus100
}

idPlus100フィールドの値を取得しようとすると、idに100足された値を取得することができる。

idPlus100フィールドを取得しなければ、resolveFieldは実行されません。

PostsテーブルはidPlus100カラムを持っていない。

query {
  fetchPostById(id:1) {
    id
    idPlus100
  }
}
"fetchPostById": {
      "id": "1",
      "idPlus100": 101
    }

例えば既存の他のフィールドの値によって、計算した値を取得できるフィールドが欲しい時などに、
今回のようなカスタムディレクティブを作成するのが良いかなと感じました。

sqlクエリが絡むディレクティブを定義する際は、バッチローダー等を使用して、パフォーマンス問題を解決することが必須かなと思います。

今回のような+100するだけのディレクティブはフロント側でも行うことができますが、
ディレクティブで実装することにより、フロントに処理を書かずに済み、フィールドを指定するだけで、データを取得できるのが良いなと感じました。

Discussion