GraphQL on Rails

GraphQL on Rails

Simple GraphQL introduction and demonstrate steps to integrate GraphQL with a Rails backend. Talked at RubyConf China 2015.

4f0a13793bb53215c3ad94e12b0a57e8?s=128

JunChen Xia

October 12, 2015
Tweet

Transcript

  1. GraphQL on Rails ॕגล, Strikingly twitter: @xjconlimii github.com/onlimii

  2. None
  3. GraphQL?

  4. GraphQLࣁFacebook 3ଙ҅ྯॠ260Պེ᧗࿢

  5. GraphQL ෬ӧฎ SQL҅Ԟӧฎᖫᑕ᧍᥺

  6. GraphQLฎRESTful APIԏ क़ጱݚӞӻᭌೠ҅ࣁ຤Զఘ ٭ӥ҅ฎๅঅጱᭌೠ̶

  7. RESTful APIጱᳯ᷌

  8. Roundtrips /api/v1/site/:id /api/v1/site/:id/analytics ᮎ౯ݢզአᛔਧԎendpointޚѺ

  9. { “data”: { “id”: 123, “title”: “Growth…”, “permalink”: “mirandakerr”, “createdAt”:

    “some time”, “updatedAt”: “another time”, “picture”: “//image.png”, “description”: “…”, “notes”: “…”, “state”: “published”, “screenshot_url”: “…”, “isRetired”: false, … } } { “data”: { “id”: 123, “title”: “Growth…”, “permalink”: “mirandakerr”, “createdAt”: “some time”, “updatedAt”: “another time”, “picture”: “//image.png”, “description”: “…”, “notes”: “…”, “state”: “published”, “screenshot_url”: “…”, “isRetired”: false, … } } Data Over-fetching
  10. Client Feature 1(v6) Feature 2(v6) Feature 3(v6) Feature 1(v6) Feature

    1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 3(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 2(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Feature 1(v6) Server Version Hell Client
  11. ྯེᵱ࿢ጱݒๅ ᮷ᵱᥝݸᒒץද

  12. “The REST interface is designed to be efficient for large-grain

    hypermedia data transfer…” - Dr Roy T Fielding, Author of REST RESTๅᭇአԭय़ᔉଶහഝ࣋ว
  13. ԅԧכᦤଫአࣁӧݶጱਮಁᒒӥ҅᮷ํ๋অጱ አಁ֛ḵ҅ӧݶጱUIᦡᦇ޾ᵱ࿢੕ᛘԧ੒හഝ ํๅੜᔉଶഴګጱᵱ࿢̶

  14. GraphQLฎRESTful API ԏक़ጱݚӞӻᭌೠ҅ࣁ੒ හഝํๅੜᔉଶഴګᵱ࿢ ጱ෸ײ҅ฎๅঅጱᭌೠ̶

  15. { me { name } } { “me”: { “name”:

    “Junchen Xia” } }
  16. { user(id: 1) { name } } ݇හփ᭓

  17. { “me”: { “name”: “Junchen Xia”, “picture”: { “height”: 300,

    “width”: 300, “url”: “//image.png” } } } { me { name picture(size: 300) { height width url } } } ىᔮັᧃ
  18. { “me”: { “name”: “Junchen Xia”, “smallPic”: { “height”: 50,

    “width”: 50, “url”: “//image.png” }, “bigPic”: { “height”: 300, “width”: 300, “url”: “//bigimage.png” } } } { me { name smallPic: picture(size: 50) { height width url } bigPic: picture(size: 300) { height width url } } } { me { name smallPic: picture(size: 50) { height width url } bigPic: picture(size: 300) { height width url } } } alias
  19. { “me”: { “name”: “Junchen Xia”, “friends”: [ { “name”:

    “AAA” }, { “name”: “BBB” } ] } } { me { name friends { name } } } one to many
  20. { me { name smallPic: picture(size: 50) { } bigPic:

    picture(size: 300) { } } } fragment pictureParam on picture { height width url } …pictureParam …pictureParam Fragment
  21. च๜༷ஷ { me { name picture { height width url

    } } } query object field object
  22. { me { name picture { height width url }

    } } type Query { me: User user(id: Int): User }
  23. { me { name picture { height width url }

    } } type User { name: String picture(size: Int=50): Picture }
  24. { me { name picture { height width url }

    } } type Picture { height: Int width: Int url: String format: String }
  25. { name(user) { user.name } picture(user, {size}) { user.picture(size) }

    } type User { name: String picture(size: Int=50): Picture } Resolver
  26. { name(user) { user.name } picture(user, {size}) { user.picture(size) }

    } type User { name: String picture(size: Int=50): Picture } Resolver
  27. { name(user) { user.name } picture(user, {size}) { user.picture(size) }

    } type User { name: String picture(size: Int=50): Picture } Resolver
  28. Server Client /api/v1/pages/1 page, V1 /api/v2/pages/1 page, V2 /api/v3/pages/3 page,

    V3 V1 V3 V2 V1 V3 V2 REST
  29. Server Client page data V1 data V1 page data V2

    data V2 page data V3 data V3 V1 V3 V2 GraphQL
  30. Server Client ᔄࣳਧԎ ݢᚆ௔ හഝᥝ࿢ UI Big Picture ᭧໒ࢶ

  31. ྯེᵱ࿢ጱݒๅ ӧᵱᥝݸᒒץද

  32. Introspection { __schema{ types{ name fields{ name type { name

    } } } } } { "data": { "__schema": { "types": [ { "name": "Query", "fields": [ { "name": "user", "type": { "name": "User" } … }
  33. Introspection 1.ᛔۖኞ౮API෈໩ 2.ๅᇍ᭧ጱ᧣ᦶૡٍ

  34. ՗ਮಁᒒᦡᦇ޾୏ݎጱ᥯ ଶڊݎ҅զአಁ֛ḵԅ໐ ஞ҅మဩᓌܔฃ౜̶

  35. GraphQL Server

  36. ଫአ᭦ᬋ ᔄࣳਧԎ Graphql-ruby ሿํӱۓդᎱ ? ଫአ᭦ᬋ GraphQL໐ஞ

  37. ᔄࣳਧԎ 1. ਧԎಅํݢᚆጱquery 2. ਧԎಅํobject, field੒ଫጱresolver

  38. DEMO

  39. HOWTO 1. Ⴒے Graphiql! 2. ࣁRouteӾႲے GraphQL endpoint҅ଚਠ౮ፘଫ᭦ᬋ 3. ਧԎschema

    4. ਧԎquery type 5. ਧԎbusiness objects
  40. Ⴒے GraphQL endpoint class GraphqlController < ApplicationController def query render

    json: Schema.execute( params[:query], variables: params[:variables] || {} ) end end
  41. Ⴒے GraphQL endpoint class GraphqlController < ApplicationController def query render

    json: Schema.execute( params[:query], variables: params[:variables] || {} ) end end
  42. ਧԎschema Schema = GraphQL::Schema.new(query: QueryType)

  43. ਧԎquery type QueryType = GraphQL::ObjectType.define do name "Query" description "The

    query root for this schema" field :user do type UserType argument :email, types.String argument :id, types.ID resolve -> (obj, args, ctx) do if args['id'] User.find(args['id']) else User.find_by(email: args['email']) end end end end
  44. ਧԎ query type QueryType = GraphQL::ObjectType.define do name "Query" description

    "The query root for this schema" field :user do type UserType argument :email, types.String argument :id, types.ID resolve -> (obj, args, ctx) do if args['id'] User.find(args['id']) else User.find_by(email: args['email']) end end end end
  45. ਧԎ query type QueryType = GraphQL::ObjectType.define do name "Query" description

    "The query root for this schema" field :user do type UserType argument :email, types.String argument :id, types.ID resolve -> (obj, args, ctx) do if args['id'] User.find(args['id']) else User.find_by(email: args['email']) end end end end
  46. ਧԎ query type QueryType = GraphQL::ObjectType.define do name "Query" description

    "The query root for this schema" field :user do type UserType argument :email, types.String argument :id, types.ID resolve -> (obj, args, ctx) do if args['id'] User.find(args['id']) else User.find_by(email: args['email']) end end end end
  47. ਧԎ query type QueryType = GraphQL::ObjectType.define do name "Query" description

    "The query root for this schema" field :user do type UserType argument :email, types.String argument :id, types.ID resolve -> (obj, args, ctx) do if args['id'] User.find(args['id']) else User.find_by(email: args['email']) end end end end
  48. ਧԎ query type QueryType = GraphQL::ObjectType.define do name "Query" description

    "The query root for this schema" field :user do type UserType argument :email, types.String argument :id, types.ID resolve -> (obj, args, ctx) do if args['id'] User.find(args['id']) elsif args[‘email’] User.find_by(email: args['email']) end end end end
  49. ਧԎ business objects UserType = GraphQL::ObjectType.define do name 'User' description

    'A user' field :id, !types.ID field :name, types.String, property: :name field :email, types.String, property: :email field :picture, types.Picture, property: :picture end resolve -> (o, a, c) { o.public_send(property) }
  50. ଫአ᭦ᬋ ᔄࣳਧԎ GraphQL໐ ஞ REST API

  51. One more thing

  52. GraphQL Mutation!

  53. mutation { changePicture(picture: p){ me { picture { url }

    } } }
  54. ecosystem

  55. ݎ઀ሿᇫ 1. graphql https://github.com/facebook/graphql 2. graphql-ruby https://github.com/rmosolgo/graphql-ruby 3. graphql-js https://github.com/graphql/graphql-js

    4. graphql awesome list https://github.com/chentsulin/ awesome-graphql
  56. ௛ᕮ 1.ࣁੜᔉଶහഝഴګᵱ࿢ӥྲRESTๅঅ 2.ඪ೮᧛ٟ҅ฎਠෆጱහഝൈᬿ᧍᥺ 3.᭗አᥢ᝜҅ݢአձ֜᧍᥺ࣁձ֜ଘݣਫሿਮಁᒒ҈๐ۓᒒ 4.՗አಁ֛ḵ޾ਮಁᒒᦡᦇڊݎ 5.Өሿํapplicationᕮݳݝᵱࣁ๐ۓᒒୌᒈᔄࣳਧԎ 6.ݢӨREST APIوਂ

  57. Q&A