Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

GraphQL

社内勉強会向けの資料です。

  • Be the first to comment

  • Be the first to like this

GraphQL

  1. 1. ・GraphQLってなに?
  RESTとの違いなど ・GraphQLのスキーマ
  Query と Mutation ・GraphQL DeepDive 今日お話しすること
  2. 2.
  3. 3. WebAPI WebApp (SPA) iOS App Android App http/s バックエンド json REST
 JSON-RPC
 GraphQL フロントエンド 昨今のアプリ
  4. 4. ・WebAPIで流行っているアーキテクチャ ・分かりやすい統一されたインターフェース
 
   GET /Users - ユーザ一覧を取得
   GET /Users/999 - ID:999ユーザを取得
   POST /Users - ユーザを登録
   PUT /Users/999 - ID:999ユーザを更新
   DELETE /Users/999 - ID:999ユーザを削除 ・Twitter, Amazon, Facebook, Githubなどで採用! RESTいいよね!
  5. 5. でも・・・つらい
  6. 6. コメント一覧 フィード一覧 コメントのコメント一覧 いいね一覧 友達一覧 コメントのいいね一覧 何がつらいか?
  7. 7. ・関連リソース
  記事一覧、コメント一覧…etc
  通信が増えてレンダリングが遅く。 ・いらない項目
  ユーザのニックネームだけ表示に
  使いたいのに住所情報まで取れたり。 ・互換性の維持
  APIのバージョニング。 RESTのつらさ
  8. 8. なに?
 ・Facebookが2012年から開発
 ・API向けのクエリ言語
 ・仕様であり実装ではない 
 特徴は?
 ・1リクエストで関連リソースを一気に取得!
 ・クライアントが使う必要なデータだけを抽出! http://graphql.org/code/ そこで ですよ
  9. 9. RESTful GraphQL 最近グググーってきてます
  10. 10. Github の採用が後押し
  11. 11. Netflixが開発した            ってのもある 参考までに
  12. 12.
  13. 13. ・Schema と Types
  GraphQL schema languageを使って
  Queries と Mutationの構造を定義 ・Queries と Mutation
  Queries :データ取得

  Mutations:データ変更 GraphQL
  14. 14. schema {
 query : Query
 mutation : Mutation
 } schema ここでのQueryとMutationは型。
 Query と Mutationをさらに定義していく。
  15. 15. Query Schema
  16. 16. type Character {    … GraphQL Object Type
 name: String!     … 文字列、Nullはダメ
 appearsIn: [Episode]! … Episode の配列 … [] or [a,b]
 } enum Episode { … ENUMも定義できる
 NEWHOPE
 EMPIRE
 JEDI
 } 使える型 … Int / Float / String / Boolean / ID / 自分が定義したtype Object types と fields
  17. 17. myField : [String!] myField: null // ok
 myField: [] // ok
 myField: [a,b] // ok
 myField: [null,a] // ng myField : [String]! myField: null // ng
 myField: [] // ok
 myField: [a,b] // ok
 myField: [null,a] // ok List と Non-Null 「!」の位置で意味が変わるよ
  18. 18. type Character {
 id : ID!
 name : String!
 length(unit: LengthUnit = METER) : Float
 } Arguments 引数を持たせることもできる
  19. 19. interface Character {
 id : ID!
 name : String!
 } type Human implements Character {
 id : ID!
 name : String!
 starships : [Starship]
 } type Droid implements Character {
 id : ID!
 name : String!
 primaryFunction : String
 } interfaces
  20. 20. Droid にしかないフィールド interfaces Droidの時は取得ってやる エラーになる!
  21. 21. union SearchResult = Human | Droid | Starship Union Types 複数の型をまとめて定義することができるが 個人的にこのレスポンスは情報が混ざっていて嫌い
  22. 22. type Query {
 hero(episode: Episode) : Character
 droid(id : ID!) : Droid
 } Query 最後に統合してQueryを定義
  23. 23. Mutation Schema
  24. 24. input ReviewInput {
 stars : Int!
 commentary : String
 } ・input には input型しか参照できない
 ・Argumentsも使用できない
 input
  25. 25. mutation CreateReviewForEpisode($ep: Episode!, $re : ReviewInput) {
 createReview(episode: $ep, review:$re) {
 stars
 commentary
 } 
 } mutation 変数 ・エピソードとレビューを受けて、レビューを作成
 ・クライアントにはスターと解説を返却する
  26. 26. type Mutation {
 createReview(episode: $ep, review:$re) : CreateReviewForEpisode
 } Mutation 最後に統合してMutationを定義
  27. 27. Query
  28. 28. {
 hero {
 name
 }
 } {
 "data": {
 "hero": {
 "name": "R2-D2"
 }
 }
 } Request Response Queries - Fields 取得するフィールドを明示的に指定するので
 フィールドが増えても無駄な通信量が増えない つまり「name」を「fullname」に仕様変更する時
 新フィールドで追加してもクライアントには影響なし!
  29. 29. {
 human(id: "1000") {
 name
 height(unit: FOOT)
 }
 } {
 "data": {
 "human": {
 "name": "Luke Skywalker",
 "height": 5.6430448
 }
 }
 } Request Response Queries - Arguments id:1000を頂戴 単位はfootで
  30. 30. {
 empireHero: hero(episode: EMPIRE) {
 name
 }
 jediHero: hero(episode: JEDI) {
 name
 }
 } {
 "data": {
 "empireHero": {
 "name": "Luke Skywalker"
 },
 "jediHero": {
 "name": "R2-D2"
 }
 }
 } Request Response Queries - Aliases episodeがEMPIREのデータは「empireHero」
 JEDIのデータは「jediHero」というフィールドで取得
  31. 31. {
 leftComparison: hero(episode: EMPIRE) {
 ...comparisonFields
 }
 rightComparison: hero(episode: JEDI) {
 ...comparisonFields
 }
 }
 fragment comparisonFields on Character {
 name
 appearsIn
 friends {
 name
 }
 } {
 "data": {
 "leftComparison": {
 "name": "Luke Skywalker",
 "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"],
 "friends": [
 {"name": "Han Solo"}, {"name": "Leia Organa"},
 {"name": "C-3PO"}, {"name": "R2-D2"}
 ]
 },
 "rightComparison": {
 "name": "R2-D2",
 "appearsIn": [ "NEWHOPE", "EMPIRE", "JEDI"],
 "friends": [
 {"name": "Luke Skywalker"},
 {"name": "Han Solo"},
 {"name": "Leia Organa"}
 ]}}} Request Response Queries - Fragments 再利用可能なフィールドセットを定義できる
  32. 32. query HeroNameAndFriends($episode: Episode) {
 hero(episode: $episode) {
 name
 friends {
 name
 }
 }
 } VALIABLES
 {
 "episode": "JEDI"
 } {
 "data": {
 "hero": {
 "name": "R2-D2",
 "friends": [
 {
 "name": "Luke Skywalker"
 },
 {
 "name": "Han Solo"
 },
 {
 "name": "Leia Organa"
 }
 ]
 }
 }
 } Request Response Queries - Variables 値を外部から渡す
  33. 33. Mutation
  34. 34. mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
 createReview(episode: $ep, review: $review) {
 stars
 commentary
 }
 } VARIABLES
 {
 "ep": "JEDI",
 "review": {
 "stars": 5,
 "commentary": "This is a great movie!"
 }
 } {
 "data": {
 "createReview": {
 "stars": 5,
 "commentary": "This is a great movie!"
 }
 }
 } Request Response Mutations ・エピソードとレビューを受けて、レビューを作成
 ・クライアントにはスターと解説を返却する
  35. 35. ・Validation ・Execution ・Introspection Deep Dive
  36. 36. Validation Queryのチェック
  37. 37. {
 hero {
 ...NameAndAppearances
 friends {
 ...NameAndAppearances
 friends {
 ...NameAndAppearances
 }
 }
 }
 } fragment NameAndAppearances on Character {
 name
 appearsIn
 } {
 "data": {
 "hero": {
 "name": "R2-D2",
 "appearsIn": [
 "NEWHOPE",
 "EMPIRE",
 "JEDI"
 ],
 "friends": [
 {
 "name": "Luke Skywalker",
 "appearsIn": [
 "NEWHOPE",
 "EMPIRE",
 "JEDI"
 ],
 "friends": [
 {
 "name": "Han Solo",
 "appearsIn": [ Request Response 階層数チェック fragment の無限循環が起きないように循環参照はエラーとする
  38. 38. 他にも ・存在しないフィールドの指定
 ・型そのものの指定
  ({ hero } -> { hero {name} }
 ・異なるインターフェースのフィールド 
 GraphQLは仕様なので実装は自分でやる
  39. 39. Execution やってみよう!
  40. 40. Base Information { "data": { "human": { "name": "Han Solo", "appearsIn": [ "NEWHOPE", "EMPIRE", "JEDI" ], "starships": [ { "name": "Millenium Falcon" }, { "name": "Imperial shuttle" } ] } } } Schema Query Request Response
  41. 41. Query: {
 human(obj, args, context) {
 return context.db.loadHumanByID(args.id).then(
 userData => new Human(userData)
 )
 }
 } obj : previous object, ルートではあまり使うことはない
 args : query の argument
 context : ユーザーやDBアクセスのようなコンテキスト情報を保持 javascript sample Root type IDを元にDBからHumanを取得
 Promiseを返却
  42. 42. Human: {
 name(obj, args, context) {
 return obj.name
 }
 } Humanオブジェクトが使える状態になったので
 フィールドの値も何を返却するのか定義する。 Trivial Resolvers
  43. 43. Human: {
 starships(obj, args, context) {
 return obj.starshipIDs.map(
 id => context.db.loadStarshipByID(id).then(
 shipData => new Starship(shipData)
 )
 )
 }
 } List Resolvers StarshipのID一覧を元にからStarshipを取得
 Promiseのリストを返却
  44. 44. Introspection 自己分析
  45. 45. {
 __type(name: "Droid") {
 name
 fields {
 name
 type {
 name
 kind
 ofType {
 name
 kind
 }
 }
 }
 }
 } スキーマ情報の確認 {
 "data": {
 "__type": {
 "name": "Droid",
 "fields": [
 {
 "name": "name",
 "type": {
 "name": null,
 "kind": "NON_NULL",
 "ofType": {
 "name": "String",
 "kind": "SCALAR"
 } } },
 {
 "name": "friends",
 "type": {
 "name": null,
 "kind": "LIST",
 "ofType": {
 "name": "Character",
 "kind": "INTERFACE"
 } } }, 定義したスキーマの有効活用!
  46. 46. Express + GraphQL
  47. 47. const schema = buildSchema(` type Query { hello: String world: String } `); const root = { hello: () => 'Hello!', world: () => 'World!', }; const app = express(); app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: root, graphiql: true, })); app.listen(4000)); sample express
  48. 48. curl localhost:4000/graphql 
 -d '{"query":"{hello}"}' -H "Content-Type:application/json" curl localhost:4000/graphql 
 -d '{hello}'
 -H “Content-Type:application/graphql" sample curl application/graphql !!
  49. 49. https://developer.github.com/v4/explorer/ せっかくなのでGithubのGraphQLAPIをさわってみよう
  50. 50. ・結局なんだったか
  ・API向けのクエリ言語
  ・仕様であり実装ではない
  ・QueryとMutationを定義する ・何がいいのか
  ・関連リソースを一気に取得!
  ・必要なデータだけを抽出
  ・バージョン互換性問題に強い まとめ
  51. 51. ・実装は難しそう ・性能問題が起きやすそう ・ドキュメントが少ないのがつらい ・RESTの問題を解決しているが
  データ操作系は仕様がブレそう ・BFFにいいかもしれない 所感
  52. 52. Backend For Frontend WebApp (SPA) iOS App Android App http/s バックエンド json フロントエンド users REST
 microservice auth articles comments favorites GraphQL
  53. 53. 試してみよう!
 React + GraphQL + Relay https://facebook.github.io/relay/docs/tutorial.html ♪

×