概要
GraphQLでクエリをしたときにそのクエリの複雑度がどの程度だったのかを把握したくなることがあります。
この問題を解決する手段として複雑度をHTTPレスポンスヘッダで応答できるようにしてみます。
このAPIデザインがどの程度一般的なのかはちゃんとわかっていないのですが、Contentful の GraphQL Content API にはレスポンスヘッダで複雑度を応答するデザインが含まれていましたので特別に異常なことではないでしょう。
コード
複雑度の計算をするアナライザとして GraphQL::Analysis::AST::QueryComplexity
が標準で提供されていますので、これを継承してアナライザーを実装します。
OverseQueryComplexityComplexityAnalyzer
をクラスを作り、#result
メソッドをオーバーライドし 、ここではGraphQL::Analysis::AST::QueryComplexity#result
で計算された複雑度を context
に設定します。
また実装したアナライザーを有効にするために query_analyzer
を使って宣言します。
class ObserveQueryComplexityAnalyzer < GraphQL::Analysis::AST::QueryComplexity
def result
complexity = super
context = query.context if query
context[:query_complexity] = complexity if context
complexity
end
end
class MySchema < GraphQL::Schema
query_analyzer(ObserveQueryComplexityAnalyzer)
end
GraphqlController#execute
では context
から 複雑度を取り出し response.headers
に設定します。
class GraphqlController < ApplicationController
X_GRAPHQL_QUERY_COMPLEXITY = 'X-GraphQL-Query-Complexity'.freeze
def execute
result = MySchema.execute(params[:query],
variables: ensure_hash(params[:variables]),
context: context,
operation_name: params[:operationName])
query_complexity = context[:query_complexity]
response.headers[X_GRAPHQL_QUERY_COMPLEXITY] = query_complexity if query_complexity
render json: result
end
private
def context
@context ||= {}
end
end
cURL などでクエリして複雑度が応答されるか確認しましょう。
$ curl -vvv -H'Content-type: application/json' \
-d'{ "query": "query { viewer { id name } }" }' \
-XPOST $GRAPHQL_ENDPOINT 2>&1 | \
grep x-graphql-query-complexity
< x-graphql-query-complexity: 3