🌲

GraphQL APIでのクライアントエンジニアのレビューの勘所

2024/12/24に公開

普段はiOSアプリの開発をしています。業務の中でクライアントエンジニア視点でGraphQL APIのレビューをすることもあるので、その勘所をまとめて都度追記していきます。

この記事でのAPI実装の例は、RailsアプリケーションにGraphQLRubyを導入したものとします。

破壊的な変更がないか

ただの追加ではなく既存fieldに対して破壊的な変更をすると、クライアントの使用状況によってクライアントでpartial dataしか取れなくなったり、クエリそのものが無効になるようなエラーになってしまいます。
なので新規追加以外の変更が既存の部分にある場合は注視する必要があります。

# before
field :product, Objects::ProductType, null: true do
  argument :id, Int, required: true
end
# after
# idのTypeが破壊的に変更されている
field :product, Objects::ProductType, null: true do
  argument :id, ID, required: true
end
query exampleQuery {
  product(id: 1) {
    name
  }
}

基本的に各Typeやargumentなどを変えたい場合は新しいfieldを追加することになります。古いfieldは非推奨フラグを立て利用率が一定以下などの任意の基準になった時点で削除します。これはクライアントが自由にクエリを設定できるので無駄なfieldが一時的に残ることが許容しやすいためよく行われます。破壊的な依存が入っている場合はこういった観点で許容できそうかレビューします。

モデルのデータ構造に依存しすぎていないか

クライアントで作品カードを表示する事を考えます。ここで作品が新着作品の場合に「新着」とラベルを表示したいとします。

例1

データベースの内容を愚直に実装したようなAPIでは以下のようになるかもしれません。
これはAPI自体が一般公開されていて幅広いクライアントがある際は、新着作品の範囲もクライアントによって違う可能性がありますし良いかもしれません。

query exampleQuery {
  product(id: 1) {
    createdAt
  }
}

例2

新着作品の範囲が概ね同じ場合は、APIで範囲を決めてisNewのようなフラグを返すのも良いかもしれません。

query exampleQuery {
  product(id: 1) {
    isNew
  }
}

例3

他の種類のラベルがある場合は以下のようにデータベースやモデルのデータ構造にとらわれずProductに対するラベルを定義するのも良いかもしれないです。

query exampleQuery {
  product(id: 1) {
    labels {
        title
    }
  }
}

クライアントファーストを考えると、このように設計の方針やAPIの公開範囲によってデータベースやモデルの設計から大きく変えた方が良い場合も多くあります。

適切な公開範囲か

GraphQLは木構造的にデータが取得できてしまうので、意図しないユーザーなどの公開範囲に対してデータが見えてしまう不具合を生むことが多々あります。

GraphQLRubyにはauthorized?やvisible?などの絞り込みの仕組みがあるので、これらを使って適切に確認できているか確認します。また、特定のTypeが使い回される場合などはときに以前意図した公開範囲と違う場合があるので注視します。

# 良くない例ですがクライアントでは作成後3ヶ月しか公開されないなどある場合
class Types::Objects::ProductType < Types::Objects::BaseObject
  field :id, ID, null: false
  field :created_at, GraphQL::Types::ISO8601DateTime, null: false
  def self.authorized?(object, context)
     object.created_at > Time.current.ago(3.month)
  end
end

Discussion