GraphQL Schema Design @ Scale

GraphQL Schema Design @ Scale

GraphQL Schema Design and Tooling @ GitHub

F34d97ba1bfea0ff5e35a9c198562402?s=128

Marc-Andre Giroux

November 07, 2018
Tweet

Transcript

  1. Marc-Andre Giroux @___xuorig___ GraphQL Summit - Nov 7th 2018 GraphQL

    Schema Design @ scale
  2. about { xuorig } • Montreal, Canada ☃ • My

    3rd GraphQL Summit • I work at GitHub! 2
  3. 3

  4. GraphQL @ GitHub • 200+ engineers working on GraphQL schema

    • Teams have to move quickly • Public and Internal Schema + Enterprise. 4
  5. GraphQL @ GitHub: Challenges • Keeping a high quality public

    API across many teams and use cases. • Small API team • Best practices are still emerging, lots and lots of PR reviews to go through, and many new use cases appearing every week. 5
  6. Why GraphQL? 6

  7. A type system to express possibilities 7

  8. Declarative: Clients select what they need and nothing more 8

  9. Why do we design? 9

  10. Why we design • Build APIs that are easier to

    evolve: Best way to mitigate breaking changes we don't know about yet • Build APIs that are easier to reason about 10
  11. GraphQL Schema Design 11

  12. Misconceptions 12

  13. In a complex application GraphQL is rarely an interface to

    your database 13
  14. Your GraphQL Schema does not need to match your existing

    REST resources 14
  15. It also does not have to be a 1:1 mapping

    to your UI 15
  16. The real power of GraphQL 16

  17. GraphQL lets us model an interface to our core domain

    17
  18. For a lot of us, it is often an opportunity

    to design from scratch (and maybe get it right this time? ) 18
  19. To let go of our coupling to our database schema,

    our REST resources or our UI 19
  20. Major to a well designed GraphQL API 20

  21. 21

  22. • Be an expert at your domain, understand the ins

    and out 21
  23. • Be an expert at your domain, understand the ins

    and out • Be an expert at GraphQL specific design 21
  24. But there's one problem... 22

  25. 23

  26. Rarely the same people! 24

  27. API First 25

  28. Built by the product team 26

  29. Helped by the API team! ❤ 27

  30. Design Tips 28

  31. Design Tips 29

  32. Guiding Principles 30

  33. Guiding Principles 31 (and some cool tools)

  34. Design for behaviors or use cases over data 32

  35. Anemic GraphQL ™ 33

  36. 34

  37. 35

  38. 36

  39. 37

  40. 38

  41. 39

  42. 40

  43. Atomicity vs Granularity 41

  44. 42

  45. Let's go back a few years... 43

  46. Problem: Multiple clients with very different needs 44

  47. 45 Backend For Frontend Pattern http://philcalcado.com/2015/09/18/the_back_end_for_front_end_pattern_bff.html

  48. 46 Netflix: Client Optimized API Adapters https://medium.com/netflix-techblog/embracing-the-differences-inside-the-netflix-api-redesign

  49. 47

  50. In a way... GraphQL is our BFF / Client Adapter

    48
  51. Declarative & Client Centric 49

  52. Select * 50

  53. Select * 51

  54. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 52
  55. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 53
  56. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 54
  57. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 55
  58. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 56
  59. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 57
  60. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 58
  61. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 59
  62. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 60
  63. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 61
  64. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 62
  65. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 63
  66. type User { billingInfo: BillingInfo! email: String! login: String! fullName:

    String! recentIssues: [Issue!]! repositories: [Repository!]! reviewRequests: [ReviewRequest!]! isOwner(repositoryID: ID!): Boolean! starredRepositories: [Repository!]! } 64
  67. We shouldn't be afraid of adding use cases or client

    specific fields if it fits a domain use case 65
  68. Stay away from trying to build a "One Size Fits

    All" API 66
  69. and embrace the different use cases and clients 67

  70. Prefer highly optimized fields over generic/smart fields 68

  71. 69

  72. 70

  73. Design @ Scale: GitHub's Tooling 71

  74. 72 Checked-in SDL

  75. 73 Checked-in SDL

  76. 74

  77. 75

  78. 76

  79. 77

  80. 78 ) GraphQL Doctor

  81. 79

  82. 80

  83. 81

  84. Sometimes we make mistakes 82

  85. 83

  86. 84

  87. 85

  88. 86

  89. 87

  90. 88

  91. 89 Fake it 'till you make it!

  92. 90

  93. Making the change 91

  94. Who is using the field? 92

  95. How much is it being used? 93

  96. No Select *: We know exactly how our schema is

    used! 94
  97. 95 query { viewer { login email } }

  98. 95 query { viewer { login email } } GitHub

    API
  99. 96 query { viewer { login email } } GitHub

    API
  100. 96 query { viewer { login email } } GitHub

    API GraphQL Query Analytics
  101. 97 query { viewer { login email } } GraphQL

    Query Analytics Type: Query Field: viewer App: xxx Type: User Field: login App: xxx ...
  102. 98 Type: Query Field: viewer App: xxx Type: User Field:

    login App: xxx ...
  103. 99 Type: Query Field: viewer App: xxx Type: User Field:

    login App: xxx ...
  104. 100

  105. 101

  106. GraphQL Schema Design @ Scale 102

  107. Talk to, (or become) domain experts 103

  108. Think Domain over Data 104

  109. Sometimes it's not about "One Size Fits All" 105

  110. Use the schema to build (or use) great tools! 106

  111. Marc-Andre Giroux @___xuorig___ GraphQL Summit - Nov 7th 2018 Thank

    You!