iOS | Apollo を使って GraphQL を使えるようにする
GraphQL クライアントである Apollo を iOS プロジェクトに導入して GrapshQL を使えるようにするまでの流れを備忘録として残しておきます。
全体の流れ
公式ドキュメント Get Started に記載されている内容にしたがって進めていきます。
- Apollo フレームワークのインストール
- スキーマファイルのダウンロード
-
.graphql
ファイルにオペレーションを記述 - code generation の設定と実行
- ApolloClient の生成
- オペレーションを実行してデータを取得
※ 今回は 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 がダウンロードできました。
.graphql
ファイルにオペレーションを記述
3. プロジェクト内に 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-type
は embeddedInTarget
、--target-name
はプロジェクトが持っているターゲット名にする。
設定ファイルの初期値は以下のとおり。
{
"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
を変更します。
"schemaSearchPaths" : [
"./schema.json"
]
設定ファイルから見て同じ階層に schema.json があるので、上記のような設定にしています。
これでもう一度実行します。
$ ./Pods/Apollo/apollo-ios-cli generate
自身で設定したスキーマ名のディレクトリが生成され、中には .graphql.swift
ファイルが入っています。このディレクトリをプロジェクト内に手動で格納します。
5. ApolloClient の生成
ここの書き方のせいで少し詰まったので注意が必要です。
生成した ApolloClient は、必ずシングルトンクラス内で保持する必要があります。自分の場合は以下のようなクラスを作りました。
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 クエリを実行してみます。
query HeroName {
hero {
name
}
}
特別難しいことはなく、fetch()
の引数に クエリ名を渡すだけです。
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