Open11

SwiftUIでGraphQLを使う準備

sakutarosakutaro

Schemaの取得

サンプルとしてGithubのschemaを取得する。
こちらを参考に。
https://zenn.dev/nekoshita/articles/7c454e8e552c0d

Githubのトークンを発行。
https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token

schema取得のclientはapolloを使う。

npm install -D apollo

or

npm install -g apollo
apollo schema:download --endpoint=https://api.github.com/graphql --header="Authorization: Bearer <token>"

動かんやん・・・

NodeのVerが16だったので14に下げて試みる

動いた

-----------------------------------------------------------------
DEPRECATED: This command will be removed from the `apollo` CLI in 
its next major version. Replacement functionality is available in 
the new Apollo Rover CLI: https://go.apollo.dev/t/migration
-----------------------------------------------------------------

  ✔ Loading Apollo Project
  ✔ Saving schema to schema.json

いずれ Rover CLIに切り替わるのかな。

sakutarosakutaro

CodeGeneratorの設定

TARGETS -> Build Phase

+ボタンを押して、New Run Script Phaseでスクリプトを追加。

名前をGenerate Apollo GraphQL APIに変更

Compile Sourcesの上に作成したスクリプトを移動します。

sakutarosakutaro

スクリプトコピーして

# Don't run this during index builds
if [ $ACTION = "indexbuild" ]; then exit 0; fi

# Go to the build root and search up the chain to find the Derived Data Path where the source packages are checked out.
DERIVED_DATA_CANDIDATE="${BUILD_ROOT}"

while ! [ -d "${DERIVED_DATA_CANDIDATE}/SourcePackages" ]; do
  if [ "${DERIVED_DATA_CANDIDATE}" = / ]; then
    echo >&2 "error: Unable to locate SourcePackages directory from BUILD_ROOT: '${BUILD_ROOT}'"
    exit 1
  fi

  DERIVED_DATA_CANDIDATE="$(dirname "${DERIVED_DATA_CANDIDATE}")"
done

# Grab a reference to the directory where scripts are checked out
SCRIPT_PATH="${DERIVED_DATA_CANDIDATE}/SourcePackages/checkouts/apollo-ios/scripts"

if [ -z "${SCRIPT_PATH}" ]; then
    echo >&2 "error: Couldn't find the CLI script in your checked out SPM packages; make sure to add the framework to your project."
    exit 1
fi

cd "${SRCROOT}/${TARGET_NAME}"
"${SCRIPT_PATH}"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile="schema.json" API.swift

query.graphqlを作って配置。

ビルド。

失敗。。

sakutarosakutaro

apollo-iosが1.0.0-alpha.1リリースされてたのでそちらを試す。

Exact versionで1.0.0-alpha.1を指定して追加する

sakutarosakutaro

テンプレートをダウンロード
https://github.com/apollographql/iOSCodegenTemplate/tree/1.0.0-alpha

Finder上で、ダウンロードしたフォルダ構造ごとプロジェクトに配置。 not Xcode

MyProject // Source root
  | MyProject.xcodeproj
  | - MyProject // Contains app target source files
  | - MyLibraryTarget // Contains lib target source files
  | - MyProjectTests // Contains test files
  | - ApolloCodegen // Contains the swift scripting files you just downloaded and dragged in

sakutarosakutaro

Docsはこう書いてあるが

Package.swift
.package(name: "Apollo",
         url: "https://github.com/apollographql/apollo-ios.git", 
         from: "1.0.0-alpha-1")

以下に修正する

Package.swift
.package(name: "Apollo",
         url: "https://github.com/apollographql/apollo-ios.git", 
         from: "1.0.0-alpha.1")  <----ここ
sakutarosakutaro

テンプレートフォルダのSources/ApolloCodegen/main.swiftを編集
・schema出力先を修正
・エンドポイントURLをlocalhostからgithubに修正
・認証用に、Authorizationヘッダーデータを追加

main.swift

static let SchemaOutputURL: URL = {
  SourceRootURL.appendingPathComponent("graphql/schema.graphqls") //出力先を修正
}()


let endpoint = URL(string: "https://api.github.com/graphql")! 
let headers: [ApolloSchemaDownloadConfiguration.HTTPHeader] = [ApolloSchemaDownloadConfiguration.HTTPHeader(key: "Authorization", value: "Bearer YOUR_TOKEN_VALUE")]
sakutarosakutaro

Schemaのダウンロード

terminal上で、ApolloCodegenフォルダに移動後以下のコマンドを入力

swift run ApolloCodegen downloadSchema
[DEBUG - ApolloCodegenLib:ApolloSchemaDownloader.swift:275] - Downloading schema via introspection from https://api.github.com/graphql
[DEBUG - ApolloCodegenLib:ApolloSchemaDownloader.swift:286] - Successfully downloaded schema via introspection

成功。

sakutarosakutaro

Generator実行時にエラーとなるため、

ここにあるsampleを参考に
https://github.com/apollographql/apollo-ios/issues/2152

テンプレートフォルダのSources/ApolloCodegen/main.swiftを再度編集

main.swift
static let SourceRootURL: URL = {
  let parentFolderOfScriptFile = FileFinder.findParentFolder()
  let sourceRootURL = parentFolderOfScriptFile
    .apollo.parentFolderURL() // Result: Sources folder
    .apollo.parentFolderURL() // Result: ApolloCodegen folder
    .apollo.parentFolderURL() // Result: Project source root folder
    .appendingPathComponent("Shared")
    .appendingPathComponent("GraphQL")
  return sourceRootURL
}()
main.swift
static let SchemaOutputURL: URL = {
  SourceRootURL.appendingPathComponent("schema.graphqls") //出力先を修正
}()


let targetRootURL = SourceRootURL
  .appendingPathComponent("Generated")
main.swift
struct GenerateCode: ParsableCommand {
  static var configuration = CommandConfiguration(
    commandName: "generate",
    abstract: "Generates swift code from your schema + your operations based on information set up in the `GenerateCode` command.")

  func run() throws {
    // TODO: Replace the placeholder here with the name of the folder containing your project's code files.
    /// The root of the target for which you want to generate code.
    let targetRootURL = SourceRootURL
      .appendingPathComponent("Generated")

    // TODO: Replace the placeholder here with the name you would like to give your schema.
    /// The name of the module that will contain your generated schema objects.
    let generatedSchemaModuleName: String = "API"

    /// The URL where the generated schema files will be written to.
    let schemaModuleURL = targetRootURL
      .appendingPathComponent(generatedSchemaModuleName)

    // Make sure the folders exists before trying to generate code.
    try FileManager.default.apollo.createDirectoryIfNeeded(atPath: targetRootURL.path)
    try FileManager.default.apollo.createDirectoryIfNeeded(atPath: schemaModuleURL.path)

    // Create the Codegen configuration object. For all configuration parameters see: https://www.apollographql.com/docs/ios/api/ApolloCodegenLib/structs/ApolloCodegenConfiguration/
    let codegenConfiguration = ApolloCodegenConfiguration(
      input: ApolloCodegenConfiguration.FileInput(
        schemaPath: SchemaOutputURL.path,
        searchPaths: [SourceRootURL.path.appending("/**/*.graphql")]
      ),
      output: ApolloCodegenConfiguration.FileOutput(
        schemaTypes: ApolloCodegenConfiguration.SchemaTypesFileOutput(
          path: schemaModuleURL.path,
          dependencyAutomation: .swiftPackageManager(moduleName: generatedSchemaModuleName)),
        operations: .inSchemaModule
      )
    )

    // Actually attempt to generate code.
    try ApolloCodegen.build(with: codegenConfiguration)
  }
}