iOS x GraphQLの嬉しみとツラミ

43.3K Views

March 07, 21

スライド概要

iOSDC 2018で発表した資料です。

profile-image

サービス開発してます。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

(ダウンロード不可)

関連スライド

各ページのテキスト
1.

iOS × GraphQL の嬉しみとツラミ iOSDC 2018 @̲mogaming

2.

About Me • Twitter: @̲mogaming • DeNAで小説系サービスの開発担当 - • iOS/Android App BFFやAPIの開発もしています 2

3.

今日話すこと 1. GraphQL API クライアント編 2. GraphQL API サーバー編 3. GraphQL API iOSから叩く編 4. GraphQLの嬉しみとツラミ 5. BFFを活用してツラミに立ち向かってみた話 3

4.

GraphQLとは APIサーバーに取り入れることのできるクエリ言語 • - RESTfulやgRPCとは全く違う思想でできている • - • Facebook作 https://graphql.org/ RESTful API GraphQL API gRPC SQLライクにAPIに問い合わせてデータを取得する 4

5.

早速GraphQL APIを叩いてみよう! 今からGithubのGraphQL APIを題材にして 実際にAPIを叩く話をしていきます💪 https://developer.github.com/v4/explorer/ 5

6.

と…その前に 少しだけ言葉の説明 " 6

7.

リクエストの種類 • Query: RESTでいうとGET • Mutation: RESTでいうとPOST, PUT, DELETE GraphQLの特徴はQueryに集中しているためQueryの話をします 7

8.

早速GraphQL APIを叩いてみよう! 今からGithubのGraphQL APIを題材にして 実際にAPIを叩く話をしていきます💪 https://developer.github.com/v4/explorer/ 8

9.

開いてみるとこんな感じ なんかエディタみたいなのが開く…ナニコレ🤔? 9

10.

GraphiQL(ぐらふぃくる?ぐらふぃかる?) • GraphiQLはブラウザで見れるGraphQL IDE • 型/Query/Mutationが一覧できる • Query/Mutationを書いて実行できる • 入力補完が効く • 導入はとっても簡単 https://github.com/graphql/graphiql 10

11.

GraphiQLの使い方 RUN Documentが見れる ここに書く ここに結果が出る jsonで変数定義 11

12.

実際に取得してみよう! Userの情報を取得(=Query)してみる💪 12

13.

DocumentからUserを取得するQueryを探す ここを押す 13

14.

userを取得してみる Queryを選択 Query一覧 userを検索 14

15.

userを取得してみる user queryの説明 返される型 User Typeから取れるFields これを取ってみる Queryの引数 15

16.

GraphQL APIの特徴 1.SQLライクにかける 2.必要なデータだけを1回で取得できる 3.interfaceに型がある 4.Paginationの仕様が決められている - ライブラリによっては実装されていなこともある 16

17.

userを取得してみる SELECT bio FROM user WHERE login = ʻmogaming217ʼ みたいなイメージ 17

18.

userを取得してみる 取得できた👏 18

19.

GraphQL APIの特徴 1.SQLライクにかける 2.必要なデータだけを1回で取得できる 3.interfaceに型がある 4.Paginationの仕様が決められている - ライブラリによっては実装されていなこともある 19

20.

必要なfieldだけ取得する avaterUrlも追加で取得する 20

21.

複数のQueryを同時に投げる facebook/graphql リポジトリも取得してみる 21

22.

複数のQueryを同時に投げる 複数APIにGETリクエストを送りがちな Top画面とかで活用できそう😊 22

23.

GraphQL APIの特徴 1.SQLライクにかける 2.必要なデータだけを1回で取得できる 3.interfaceに型がある 4.Paginationの仕様が決められている - ライブラリによっては実装されていなこともある 23

24.

型がしっかりある: Nullability Nullabilityが ! でわかる 24

25.

型がしっかりある: Enum リポジトリに対する Permissionのfield Permissionとして返ってくる 値がEnumとして定義されている 25

26.

型がしっかりある 実体としてはStringが返ってくる 26

27.

型がしっかりある • あらゆるfieldに型を付けられる • 型に適合できていない場合は型システムがエラーを返す 27

28.

GraphQL APIの特徴 1.SQLライクにかける 2.必要なデータだけを1回で取得できる 3.interfaceに型がある 4.Paginationの仕様が決められている - ライブラリによっては実装されていなこともある 28

29.

Pagination • 例:ユーザーがスターしているリポジトリを取得する • たくさんあるかもしれないので全件取得はキビシイ • そういう場合のための Connection という型 - 今回の場合だと StarredRepositoryConnection 29

30.

ConnectionType: Arguments 取得したい件数を指定するために argumentsとして first または last を必ず渡す必要がある 最初のn個 最後のn個 30

31.

ConnectionType: Return Type } 1. 結果はedges.nodeに入ってきて nodeの位置はcursorで管理される } 2. よく使うであろう情報が PageInfoとして用意されている 31

32.

ConnectionType: starredRepositoryを取得 starredRepositoryを取ってみる⭐ 最初の2件取得 pageの情報もとっておく 32

33.

ConnectionType: starredRepositoryを取得 2件だけ取得できた🌟 この位置を指している 33

34.

ConnectionType: Cursor cursorを after や before に渡せば そこを基準にしてfirst/lastを使うことができる = Pagination 34

35.

ConnectionType: Cursorを指定する 先程のendCursorをafterに渡してみる 35

36.

ConnectionType: Cursorを指定する できてる🎉 36

37.

GraphQL APIの特徴 1.SQLライクにかける 2.必要なデータだけを1回で取得できる 3.interfaceに型がある 4.Paginationの仕様が決められている - ライブラリによっては実装されていなこともある 4つの特徴とどうやってGraphQL APIを 叩くのかをご理解いただけたでしょうか? 37

38.

GraphQL サーバーサイド編 GraphQL APIサーバーはどのように 実装すればよいのか🤔? 38

39.

GraphQL サーバーサイド視点 graphql-ruby 1.8.4 の場合でお話させていただきます🙇 39

40.

UserTypeの定義 UserType 返される型 40

41.

UserTypeの定義 field名, 型, 説明, nullabilityを宣言していく 定義 と Resolver ConnectionTypeに渡された 引数に応じて勝手にLIMITと OFFSETをつけてくれる 41

42.

GraphQL サーバーサイド視点 ConnectionTypeを返すときに ほとんどそれを意識する必要がなくて素晴らしい🙄 42

43.

User queryの定義 user query 43

44.

user queryの実装 Query名(User => userになる) 返す型 user queryの引数 このqueryで返す処理 44

45.

GraphQL サーバーサイド視点 たったこれだけでuser queryが完成😭 想像以上に簡単ですよね☺? 45

46.

iOSからはどう叩く? iOSから叩くときはどうするのか? 46

47.

iOSからはどう叩く? POSTでRequest Bodyに下記を渡すだけ 47

48.

生URLSessionで頑張る 48

49.

生URLSessionで頑張る これはツラい 49

50.

つらいので ライブラリの力を借りたい😫 50

51.

GraphQLクライアントライブラリ Apollo iOS https://github.com/apollographql/apollo-ios 51

52.

Apollo iOSを使う:下準備 Apollo iOSを使うためには準備が必要です 52

53.

Apollo iOSを使う:下準備 コード生成をします 53

54.

Apollo-iOSを使う: 下準備 すべての型/Query/Mutations GraphiQLで書いた 情報が書かれている Queryをファイルとして用意 schema.json of Github GraphQL findUser.gql Apollo CLI Generate Code! Swift Code 54

55.

Apollo-iOSを使う: .gqlファイル Queryに名前をつける 55

56.

Apollo-iOSを使う 型のある世界! 56

57.

iOSからGraphQL APIを叩く Apollo iOSの力を借りれば TypeSafeにGraphQL APIを叩くことができる😊 57

58.

GraphQL APIの特徴 = GraphQLの魅力 1.SQLライクにかける 2.必要なデータだけを1回で取得できる 3.interfaceに型がある 4.Paginationの仕様が決められている これらがそのままGraphQLの魅力になる💪 58

59.

iOSアプリエンジニア的GraphQLの嬉しみ • interfaceに型がある • GraphiQLが最高 - 常に最新のドキュメントになっている いつでも試しにAPI叩けるしクエリ作れる 59

60.

サーバーサイド視点では • ⭕ クライアント毎にAPI作りわけなくて良くて楽 • ❌ 画像等のファイルをデフォルトでは扱えない - ファイルを扱う箇所だけはRESTfulにして対処している (ライブラリを入れれば扱えなくはない) • ❌ N+1問題が発生しやすくて大変 • ❌ エンドポイントが単一(/api/graphql)のためCache難しい - いままでの知見があまり使えない 60

61.

GraphQLのツラミ さて……ツラミの話をします 61

62.

GraphQLのツラミ エラーハンドリングが難しい 62

63.

エラーはどう来るのか エラーはこんな感じで来る 63

64.

GraphQLのツラミ:エラーハンドリング • 複数のQuery/Mutationを同時に叩くと一部成功して 一部失敗とかが起こりうる • どれがクリティカルなものなのかの判断が必要 いつもどおり頑張って考えてやるしかない💪 64

65.

GraphQLのツラミ statusCodeが基本200で返ってくる 65

66.

GraphQLのツラミ:statusCode • statusCodeは基本200で返ってくる • GraphQLはリクエストが通れば200 • apollo-iosからはstatusCodeが見えなくなっている • Mutation(更新系)が特にツラい 66

67.

Mutationに対する超個人的見解 • GraphQLはQueryがとても魅力的だがMutationはそれほど • 更新系はGraphQLであるありがたみがほとんどない 67

68.

GraphQLのツラミ このツラミをなんとか解決できないかな…🤔? 68

69.

statusCodeが200問題 まずGraphQL API側でエラーの内容を拡張する 69

70.

API側でエラーを拡張する GraphQL API側でエラーを拡張して statusCodeをレスポンスに付与する 70

71.

アプリ側でstatusCodeを参照する statusCodeを取り出す 71

72.

statusCodeが200問題 なんとかなってる気がする…🤔? 72

73.

しかしワイは思った 「いやワイは、Mutationの結果は 普通にStatusCodeでハンドリングしたいんじゃー😡」 73

74.

しかしワイは思った なぜかというと 74

75.

Backends For Frontends 弊サービスはMicroservices構成 iOS App BFF Payment Image/Movie Core Domain Notification RESTful RESTful GraphQL RESTful そもそもRESTful APIも叩かないといけないことがある 75

76.

BFFを用いた黒魔術 iOSからみてMutation(更新系)だけRESTっぽく 振る舞わせることもできます🧙 76

77.

BFFを用いた黒魔術 ① URLSession等で POST: /api/createNovel iOS App ⑥ HTTP StatusCode でハンドリング ② GraphQLの Mutationに マッピング ③ Mutation createNovel() BFF ⑤ errors.first.statusCodeを HTTP StatusCodeとする GraphQL API ④ “errors”: [{ “statusCode”: 400 }] 77

78.

BFFを用いた黒魔術 できました☺ 78

79.

BFFを用いた黒魔術 こういうふうにもできるよっていうだけなので オススメはしません2 もしかしたらこれがイイってなることもあるかも…? 79

80.

まとめ GraphQLはなかなかいいぞ • - interfaceに型があるの最高 GraphiQL最高 GraphQLはエラーハンドリングが結構むずかしいぞ • - BestPracticeがあまりなくとても悩ましい 懇親会や弊社DeNAブースでもいつでもお声がけください! 80

81.

参考資料 81

82.

Apollo-iOSを使う: 下準備(詳細) apolloをnpm install • - npm i -g apollo apolloを使ってGithub GraphQL APIのschemaを取得 • - apollo schema:download --endpoint=https://api.github.com/graphq --header="Authorization: Bearer <token>" schema.json • GraphiQLで書いたqueryに名前つけて.gqlファイルとして保存 • schemaと.gqlからapolloを使ってコード生成 - apollo codegen:generate --queries=findUser.gql --schema=schema.json API.swift 82