🎃

GraphQL で実行時に Query と Mutation を判別する方法

に公開

GraphQL では、Query と Mutation はスキーマ上でははっきり分かれていますが、
「実行時にどちらが呼ばれたのか?」を判別したいケースがあります。

たとえば以下のようなケースが考えられます:

Apollo Server の plugin 内で、リクエストが Query か Mutation かを判定したい

Logging / Tracing / Metrics 用に操作の種類を知りたい

Query だけ rate limit を変えたい、Mutation だけアクセス制御したい など

しかし、GraphQL の実行時コンテキスト(GraphQLResolveInfo など)には
「これは Query/Muation です」と直接分かるプロパティがありません。

解決策:info.operation.operation を使う

GraphQL のリゾルバは、第四引数として GraphQLResolveInfo(info)を受け取ります。

resolve(parent, args, context, info) {
  console.log(info.operation.operation);
}

ここで info.operation.operation には以下の値が入っています:

操作種別	            取得できる値
Query	             "query"
Mutation	    "mutation"
Subscription	  "subscription"

つまり、実行時に これだけでリクエストの種別を判定できるということです。

Apollo Server Plugin での実用例

GraphQL では、

Query は Query 型のフィールド

Mutation は Mutation 型のフィールド
としてスキーマ上に定義されます。

Apollo Server の plugin で実際に判定するには、requestDidStart フックを使います。

const plugin = {
  async requestDidStart() {
    return {
      async executionDidStart(requestContext) {
        const op = requestContext.operation?.operation;
        console.log("Operation type: ", op);
      },
    };
  }
};

ここでも operation.operation を参照するだけで Query/Muation を区別できます。

注意点

GraphQL の クライアントが operation name を省略していても判別可能

Schema の Query / Mutation のフィールドレベルでは区別できない
→ operation(=リクエスト)単位での判定のみ可能

operation はパース直後の AST (OperationDefinitionNode) に基づくため、極めて確実

まとめ

StackOverflow の回答のポイントは以下です:

GraphQL はリクエスト (operation) に対して query / mutation / subscription の情報を保持している

その情報は info.operation.operation または requestContext.operation.operation で取得できる

よって、実行時でも Query と Mutation を安全に区別できる

GraphQL のミドルウェア、ログ、権限管理などで役立つテクニックです。

Discussion