Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swiftでもapollo-iosで快適にGraphQL

 Swiftでもapollo-iosで快適にGraphQL

ymanya

May 15, 2019
Tweet

More Decks by ymanya

Other Decks in Programming

Transcript

  1. Swiftでもapollo-iosで快適にGraphQL 導入と実装ノウハウ 株式会社スペースマーケット ymanya

  2. 2 自己紹介 Yuki Manya( @ymanya ) スペースマーケットでフロントエンドチームリーダー兼 Webフロントエンド・iOSアプリエンジニアをしています。 前職はSIerでQAとか新規事業の開発とかやってました。

  3. 3 今日話すこと/話さないこと • 話すこと ◦ iOS開発でGraphQLを扱うために入れた apollo-iosがよかったこと ◦ 実装する前に知っておきたかった実装ノウハウ •

    話さないこと ◦ GraphQL自体について
  4. 4 スペースマーケットって?

  5. 5 スペースマーケットとは 時間貸し・宿泊スペースを検索・予約できるサービスです

  6. 6 ざっくりとしたサービスの構成図 クライアントサイド サーバサイド スマートフォン アプリ API(REST/GraphQL) 移行中 Web フロントエンド

    (各サービスごと)
  7. 7 現在GraphQLに絶賛移行中で、 昨年末に高速化の一環として検索APIをGraphQL化!

  8. 8 というわけで、iOSアプリでもその恩恵を受けるため、GraphQLを 引けるようにすべく、導入&実装を行いました

  9. 9 ライブラリの導入

  10. 10 apollo-iosの導入 • GraphQLを扱うライブラリとして apollo-iosを導入しました ◦ 弊社ではすでにWebフロントエンド/バックエンドで導入実績があったこと ◦ 導入するにあたってのツール類が揃っており、便利そうだったこと •

    大抵のライブラリと同様に、 CarthageとCocoaPodsで導入できます ◦ https://www.apollographql.com/docs/ios/installation
  11. 11 schema.json取得 • Apolloのツールを使うことで GraphQLスキーマの取得や、クエリから Swiftファイルを生成するのが コマンドで簡単にできるようになります • ツールはnpmパッケージとして提供されているので node.jsなどが必要となります

    npm init # 以下対話的に聞かれるのでプロジェクトに合わせて入力ください ... # Apolloのツールをインストール npm install --save-dev apollo@2.10.3 # ENDPOINTで指定したGraphQLサーバーからスキーマファイルをダウンロードし、 schema.jsonとして保存します # このスキーマファイルがクエリやミューテーションでどういう値を受け付けるかを持っている ので、コード生成のときに使用されます # なお、最新版だと公式 Docsと少しコマンドが違うので注意です npx apollo service:download --endpoint=$ENDPOINT schema.json
  12. 12 schema.jsonとGraphQLクエリからSwiftファイルを生成 • 例えば以下のようなスペースを検索するクエリを .graphqlファイルで保存します query searchRooms( $page: Int, )

    { searchRooms( page: $page, ) { results { id name } } }
  13. 13 schema.jsonとGraphQLクエリからSwiftファイルを生成 • このクエリを実行できる Swiftコードをapolloのツールからコマンド一つで生成します # クエリやミューテーションが書かれた graphqlファイルとスキーマファイルから、 Swiftのコードを生成しま す

    # namespace指定することで生成されるコードの enumの名前を任意にすることができます。 npx apollo client:codegen ./GraphQLAPI.swift --target=swift --queries=./*.graphql --localSchemaFile=./schema.json --namespace=GraphQLAPI
  14. 14 schema.jsonとGraphQLクエリからSwiftファイルを生成 • GraphQLスキーマの情報から、 Swiftコード上で も型定義されており、個人的には JavaScriptより もプログラミングしやすかったです • もちろん、GraphQLのEnumeration

    typesも Swiftのenumに変換されます • すごく簡略化していますが、上のクエリはこんな 感じで変換されます public enum GraphQLAPI { ... public final class SearchRoomsQuery: GraphQLQuery { ... public var page: Int? ... public struct Data: GraphQLSelectionSet { ... public struct SearchRoom: GraphQLSelectionSet { ... public var results: [Result?]? { ... } public struct Result: GraphQLSelectionSet { ... public var id: Int? { get { return resultMap["id"] as? Int } set { resultMap.updateValue(newValue, forKey: "id") } } ... } ... } ... } ... } ... }
  15. 15 schema.jsonとGraphQLクエリからSwiftファイルを生成 • GraphQLAPI.swiftをプロジェクトに読み込めば、 Swiftコードからは以下のような形で呼び出せる 状態になります // namespace内にquery searchRoomsがSearchRoomsQueryとして定義されているので、これを生成 します

    let searchRoomsQuery = GraphQLAPI.SearchRoomsQuery() // クエリに渡すvariablesもclass変数として定義されているので、以下のようにセットできます searchRoomsQuery.page = 2
  16. 16 ApolloClientを生成し、あとはクエリを実行する • 以下のようなコードで ApolloClientを生成 し、あとはクエリを実行します • 実際のコードではシングルトンで Apolloク ライアントを保持するようにしました

    // 追加したいHTTPヘッダがあれば var apiHeaders: [AnyHashable : Any] = [ "Accept-Language": NSLocale.current.identifier, "Accept-Timezone": NSTimeZone.default.identifier ] let configuration: URLSessionConfiguration = .default configuration.httpAdditionalHeaders = apiHeaders // GRAPHQL_ENDPOINTに接続するApolloクライントを生成 let graphqlClient = ApolloClient(networkTransport: HTTPNetworkTransport(url: URL(string: GRAPHQL_ENDPOINT)!, configuration: configuration)) // 先程のクエリとクライアントでこのようにデータ取得ができます graphqlClient.fetch(query: searchRoomsQuery) { (result, error) in guard let rooms = result?.data?.searchRooms?.results, error == nil else { // エラー時の処理 print(error) return } // 正常に取得できた時の処理 print(rooms) }
  17. 17 実装ノウハウ

  18. 18 関数で引き渡す可能性がある部分はfragment化する

  19. 19 fragmentとは • GraphQL自体が機能として持つ fragmentは、クエリ の一部を共通化できる仕組みです • スペース情報をフラグメントとして持てば、検索やお 気に入りでの同じスペース情報を取得する場合でも 再利用できる、といった形です

    query searchRooms( $page: Int, ) { searchRooms( page: $page, ) { results { ...roomFragment } } } fragment roomFragment on Room { id name }
  20. 20 fragment有り無しで書いてみた例 // fragmentを使わなかった場合 func configure(rooms: [GraphQLAPI.SearchRoomsQuery.Data.SearchRoom.Result]) { ... }

    // fragmentを使った場合 func configure(rooms: [GraphQLAPI.RoomFragment]) { ... }
  21. 21 fragment化のメリット • UIの構築メソッドなどに fragment単位で渡すことができ、別のクエリで参照している場合でも使い 回せる ◦ 公式ドキュメントにも記載がありますが、 fragment化しておくことで、それは別で structとして

    定義されるようになる • そして何よりコードが読みやすい!
  22. 22 fragment化のデメリット • fragment化した箇所で例えば on Roomで指定したRoom部分の名称についてサーバー側の変更 があると、データ取得に失敗してしまうこともあるので、注意が必要

  23. 23 開発に便利なツール

  24. 24 開発に便利なツール • XcodeでGraphQLファイルのシンタックスハイライトしてくれる Apollo製のプラグイン ◦ https://github.com/apollographql/xcode-graphql • GraphiQL /

    Insomnia ◦ スキーマを確認しながら、クエリを書き、その場で叩くこともできるツール ◦ GraphiQLはブラウザの拡張機能のほか スタンドアロンアプリ もあります ◦ REST APIも叩けるInsomniaも弊社では人気です • ビルド時に自動的にクエリファイルから Swiftコードを生成する設定もあります ◦ https://www.apollographql.com/docs/ios/installation.html#adding-build-step ◦
  25. 25 まとめ

  26. 26 まとめ • まだ移行段階ではありますが、GraphQL側に寄せたいと思えるほどには快適! ◦ GraphQLのメリットである、クライアント側が必要な情報だけをまとめて取得できる 点はもちろんメリット ◦ 加えて、型のあるSwiftではGraphQL側で定義されていることにより、 Optional含め

    て型定義されたコードが生成される点も魅力的! • GraphQL導入される場合には、クライアントライブラリとして apollo-iosはおすすめで す!
  27. 27 We're Hiring! • スペースマーケットでは全方位で絶賛採用活動中です! ◦ 特にAndroidアプリエンジニア・Webフロントエンドエンジニア・バックエンドエンジニ アなど ◦ 興味のある方は「Wantedly

    スペースマーケット」で検索orQRコード読取!
  28. None