🐷

iOS | Apollo を使って GraphQL を使えるようにする

2023/02/02に公開

GraphQL クライアントである Apollo を iOS プロジェクトに導入して GrapshQL を使えるようにするまでの流れを備忘録として残しておきます。

全体の流れ

公式ドキュメント Get Started に記載されている内容にしたがって進めていきます。

  1. Apollo フレームワークのインストール
  2. スキーマファイルのダウンロード
  3. .graphql ファイルにオペレーションを記述
  4. code generation の設定と実行
  5. ApolloClient の生成
  6. オペレーションを実行してデータを取得

※ 今回は CocoaPods を使います。

1. Apollo フレームワークのインストール

Podfile に pod "Apollo" の記述を追加して以下のコマンドを実行します。

$ pod install

2. スキーマファイルのダウンロード

ダウンロードに必要な apollo コマンドと graphql をインストールする。

$ npm install -g apollo
$ npm install -g graphql

プロジェクトのルートディレクトリで以下のコマンドを実行する。

$ npx apollo schema:download --endpoint={https://...} schema.json --header="Authorization: Bearer {ACCESS_TOKEN}"

これで schema.json がダウンロードできました。

3. .graphql ファイルにオペレーションを記述

プロジェクト内に Query などのディレクトリを作成し、その中に Xxx.graphql という名前のファイルを作ります。その中に適当なクエリやミューテーションを記述してください。

4. code generation の設定と実行

以下のコマンドで設定ファイル apollo-codegen-config.json を生成する。

Pods/Apollo/apollo-ios-cli init --schema-name {SCHEMA_NAME} --module-type embeddedInTarget --target-name {TARGET_NAME}

ドキュメントに記載されているとおり、単一ターゲットの場合 --module-typeembeddedInTarget--target-name はプロジェクトが持っているターゲット名にする。

設定ファイルの初期値は以下のとおり。

apollo-codegen-config
{
  "schemaName" : "MySchemaName",
  "options" : {
    "cocoapodsCompatibleImportStatements" : true
  },
  "input" : {
    "operationSearchPaths" : [
      "**/*.graphql"
    ],
    "schemaSearchPaths" : [
      "**/*.graphqls"
    ]
  },
  "output" : {
    "testMocks" : {
      "none" : {
      }
    },
    "schemaTypes" : {
      "path" : "./MySchemaName",
      "moduleType" : {
        "embeddedInTarget" : {
          "name" : "MyTargetName"
        }
      }
    },
    "operations" : {
      "inSchemaModule" : {
      }
    }
  }
}

次に code generation を実行します。

$ ./Pods/Apollo/apollo-ios-cli generate

ここで以下のエラーが発生しました。

Error: A GraphQL schema could not be found. Please verify the schema search paths.

スキーマファイルが見つからないようです。パスを確認しろと言われているので、設定ファイル schemaSearchPaths を変更します。

apollo-codegen-config
    "schemaSearchPaths" : [
      "./schema.json"
    ]

設定ファイルから見て同じ階層に schema.json があるので、上記のような設定にしています。
これでもう一度実行します。

$ ./Pods/Apollo/apollo-ios-cli generate

自身で設定したスキーマ名のディレクトリが生成され、中には .graphql.swift ファイルが入っています。このディレクトリをプロジェクト内に手動で格納します。

5. ApolloClient の生成

ここの書き方のせいで少し詰まったので注意が必要です。
生成した ApolloClient は、必ずシングルトンクラス内で保持する必要があります。自分の場合は以下のようなクラスを作りました。

GraphQLClient
final class GraphQLClient {
    
    static let shared = GraphQLClient()
    
    let apollo = {
        let cache = InMemoryNormalizedCache()
        let store = ApolloStore(cache: cache)
        let client = URLSessionClient()
        let provider = DefaultInterceptorProvider(client: client, store: store)
        let url = URL(string: "https://...")!
        let token = "my_access_token"
        let transport = RequestChainNetworkTransport(
            interceptorProvider: provider,
            endpointURL: url,
            additionalHeaders: ["Authorization": "Bearer \(token)"]
        )
        return ApolloClient(networkTransport: transport, store: store)
    }()
    
    private init() {}
}

ApolloClient をその場で生成して使おうとすると、sessionInvalidated のエラーが発生するので注意してください。

6. オペレーションを実行してデータを取得

あとは 3 で記述したクエリ/ミューテーションを実行するだけです。

公式ドキュメントに掲載されている HeroName クエリを実行してみます。

HeroName.graphql
query HeroName {
  hero {
    name
  }
}

特別難しいことはなく、fetch() の引数に クエリ名を渡すだけです。

HeroDetailController
let apollo = GraphQLClient.shared.apollo
apollo.fetch(query: MySchemaName.HeroNameQuery()) { result in
    guard let data = try? result.get().data else { return }
    print(data.hero.name) // Luke Skywalker
}

MySchemaName は apollo-ios-cli generate により自動生成されたクラスです。その中に HeroNameQuery というクラスも実装されています。

あとは Xxx.graphql にクエリ/ミューテーションを書く → apollo-ios-cli generate を実行 → apollo.fetch(...) でデータを取得という流れになります。

Discussion