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

No REST for the wicked: an introduction to GraphQL

1a45b192d0bbaf167afb43a41859e313?s=47 Ju Liu
January 14, 2016

No REST for the wicked: an introduction to GraphQL

GraphQL is a query language introduced by Facebook for building APIs which challenges one of the fundamental tenets of modern web development, aka REST. In this talk, we will go through the basics of GraphQL and see how it can help us build incredibly multifaceted APIs.

1a45b192d0bbaf167afb43a41859e313?s=128

Ju Liu

January 14, 2016
Tweet

Transcript

  1. No REST for the Wicked Ember London @arkham

  2. A gentle introduction to GraphQL Ember London @arkham

  3. Hello! 4 My name is Ju ! 4 I'm an

    engineer at AlphaSights 4 We build ambitious apps in Ember (talk to me!) Ember London @arkham
  4. What's this GraphQL thing? Ember London @arkham

  5. 4 A Graph Query Language 4 Invented by Facebook in

    2012, now made open 4 Powers most of the Facebook iOS and Android apps Ember London @arkham
  6. GraphQL* * Does not actually require a Graph Ember London

    @arkham
  7. A simple example Ember London @arkham

  8. We have a users table like this one +----+------+---------------+-----+-----------+ |

    id | name | twitter | age | country | +----+------+---------------+-----+-----------+ | 1 | Ju | arkh4m | 29 | Italy | | 2 | Will | willrax | 268 | Australia | | 3 | Matz | yukihiro_matz | 50 | Japan | +----+------+---------------+-----+-----------+ Ember London @arkham
  9. Get all users - Query string { users { id,

    name } } Ember London @arkham
  10. Get all users - JSON response { "data": { "users":

    [ { "id": "1", "name": "Ju" }, { "id": "2", "name": "Will" }, { "id": "3", "name": "Matz" } ] } } Ember London @arkham
  11. Get one user - Query string { user(id: 1) {

    id, name } } Ember London @arkham
  12. Get one user - JSON response { "data": { "user":

    { "id": "1", "name": "Ju" } } } Ember London @arkham
  13. Create a user - Query string mutation { user: createUser(

    name: "Tom", twitter: "tomdale", country: "USA" ) { id, name } } Ember London @arkham
  14. Create a user - JSON response { "data": { "user":

    { "id": "4", "name": "Tom" } } } Ember London @arkham
  15. Error - Query string mutation { user: createUser( twitter: "tomdale",

    country: "USA" ) { id, name } } Ember London @arkham
  16. Error - JSON response { "errors": [ { "message": "Field

    'createUser' argument 'name' of type 'String!' is required but not provided." } ] } Ember London @arkham
  17. Relationships Relationships Relationships Ember London @arkham

  18. Now imagine we have a company table like this one

    +----+-------------+---------------+ | id | name | city | +----+-------------+---------------+ | 1 | AlphaSights | London | | 2 | Heroku | San Francisco | +----+-------------+---------------+ Ember London @arkham
  19. And we add a company_id to each user +----+------+---------------+-----+-----------+------------+ |

    id | name | twitter | age | country | company_id | +----+------+---------------+-----+-----------+------------+ | 1 | Ju | arkham | 29 | Italy | 1 | | 2 | Will | willrax | 268 | Australia | 1 | | 3 | Matz | yukihiro_matz | 50 | Japan | 2 | +----+------+---------------+-----+-----------+------------+ Ember London @arkham
  20. Relationships - Query string { user(id: 1) { id, name,

    company { name } } } Ember London @arkham
  21. Relationships - JSON response { "data": { "user": { "id":

    "1", "name": "Ju", "company": { "name": "AlphaSights" } } } } Ember London @arkham
  22. Nested relationships - Query string { user(id: 1) { id,

    name, company { name employees: users { name } } } } Ember London @arkham
  23. Nested relationships - JSON response { "data": { "user": {

    "id": "1", "name": "Ju", "company": { "name": "AlphaSights", "employees": [ { "name": "Ju" }, { "name": "Will" } ] } } } } Ember London @arkham
  24. But why should I use it? Ember London @arkham

  25. 4 Hierarchical 4 Product-centric 4 Client-specifies queries 4 Backwards Compatible

    4 Structured, Arbitrary Code 4 Application-Layer Protocol 4 Strongly-typed 4 Introspective Ember London @arkham
  26. Ember London @arkham

  27. No REST for the wicked! Ember London @arkham

  28. REST request GET /users/1 Ember London @arkham

  29. REST response ??? Ember London @arkham

  30. GraphQL request { user(id: 1) { id, name } }

    Ember London @arkham
  31. GraphQL response { "data": { "user": { "id": "1", "name":

    "Ju" } } } Ember London @arkham
  32. What You See Is What You Get Ember London @arkham

  33. Every GraphQL query is a contract Ember London @arkham

  34. Every GraphQL query is a frontend-driven contract Ember London @arkham

  35. SOLID Ember London @arkham

  36. Interface Segregation Principle Ember London @arkham

  37. 4 Clients should not be forced to depend on methods

    that they do not use. Ember London @arkham
  38. 4 Clients should not be forced to depend on methods

    that they do not use. 4 Many client specific interfaces are better than one general purpose interface. Ember London @arkham
  39. 4 Clients should not be forced to depend on methods

    that they do not use. 4 Many client specific interfaces are better than one general purpose interface. 4 The dependency of one class to another one should depend on the smallest possible interface. Ember London @arkham
  40. 4 Clients should not be forced to depend on methods

    that they do not use. 4 Many client specific interfaces are better than one general purpose interface. 4 The dependency of one class to another one should depend on the smallest possible interface. 4 Make fine grained interfaces that are client specific. Ember London @arkham
  41. REST request Ember London @arkham

  42. POST /repos/ { "name": "Hello-World", "description": "This is your first

    example", "homepage": "https://example.com", "private": false, "has_issues": true, "has_wiki": true, "has_downloads": true } Ember London @arkham
  43. REST response { "id": 1296269, "owner": { "login": "octocat", "id":

    1, "avatar_url": "https://example.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.example.com/users/octocat", "html_url": "https://example.com/octocat", "followers_url": "https://api.example.com/users/octocat/followers", "following_url": "https://api.example.com/users/octocat/following{/other_user}", "gists_url": "https://api.example.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.example.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.example.com/users/octocat/subscriptions", "organizations_url": "https://api.example.com/users/octocat/orgs", "repos_url": "https://api.example.com/users/octocat/repos", "events_url": "https://api.example.com/users/octocat/events{/privacy}", "received_events_url": "https://api.example.com/users/octocat/received_events", "type": "User", "site_admin": false }, "name": "Hello-World", "full_name": "octocat/Hello-World", "description": "This your first repo!", "private": false, "fork": true, "url": "https://api.example.com/repos/octocat/Hello-World", "html_url": "https://example.com/octocat/Hello-World", "archive_url": "http://api.example.com/repos/octocat/Hello-World/{archive_format}{/ref}", "assignees_url": "http://api.example.com/repos/octocat/Hello-World/assignees{/user}", "blobs_url": "http://api.example.com/repos/octocat/Hello-World/git/blobs{/sha}", "branches_url": "http://api.example.com/repos/octocat/Hello-World/branches{/branch}", "clone_url": "https://example.com/octocat/Hello-World.git", "collaborators_url": "http://api.example.com/repos/octocat/Hello-World/collaborators{/collaborator}", "comments_url": "http://api.example.com/repos/octocat/Hello-World/comments{/number}", "commits_url": "http://api.example.com/repos/octocat/Hello-World/commits{/sha}", "compare_url": "http://api.example.com/repos/octocat/Hello-World/compare/{base}...{head}", "contents_url": "http://api.example.com/repos/octocat/Hello-World/contents/{+path}", "contributors_url": "http://api.example.com/repos/octocat/Hello-World/contributors", "downloads_url": "http://api.example.com/repos/octocat/Hello-World/downloads", "events_url": "http://api.example.com/repos/octocat/Hello-World/events", "forks_url": "http://api.example.com/repos/octocat/Hello-World/forks", "git_commits_url": "http://api.example.com/repos/octocat/Hello-World/git/commits{/sha}", "git_refs_url": "http://api.example.com/repos/octocat/Hello-World/git/refs{/sha}", "git_tags_url": "http://api.example.com/repos/octocat/Hello-World/git/tags{/sha}", "git_url": "git:example.com/octocat/Hello-World.git", "hooks_url": "http://api.example.com/repos/octocat/Hello-World/hooks", "issue_comment_url": "http://api.example.com/repos/octocat/Hello-World/issues/comments{/number}", "issue_events_url": "http://api.example.com/repos/octocat/Hello-World/issues/events{/number}", "issues_url": "http://api.example.com/repos/octocat/Hello-World/issues{/number}", "keys_url": "http://api.example.com/repos/octocat/Hello-World/keys{/key_id}", "labels_url": "http://api.example.com/repos/octocat/Hello-World/labels{/name}", "languages_url": "http://api.example.com/repos/octocat/Hello-World/languages", "merges_url": "http://api.example.com/repos/octocat/Hello-World/merges", "milestones_url": "http://api.example.com/repos/octocat/Hello-World/milestones{/number}", "mirror_url": "git:git.example.com/octocat/Hello-World", "notifications_url": "http://api.example.com/repos/octocat/Hello-World/notifications{?since, all, participating}", "pulls_url": "http://api.example.com/repos/octocat/Hello-World/pulls{/number}", "releases_url": "http://api.example.com/repos/octocat/Hello-World/releases{/id}", "ssh_url": "git@example.com:octocat/Hello-World.git", "stargazers_url": "http://api.example.com/repos/octocat/Hello-World/stargazers", "statuses_url": "http://api.example.com/repos/octocat/Hello-World/statuses/{sha}", "subscribers_url": "http://api.example.com/repos/octocat/Hello-World/subscribers", "subscription_url": "http://api.example.com/repos/octocat/Hello-World/subscription", "svn_url": "https://svn.example.com/octocat/Hello-World", "tags_url": "http://api.example.com/repos/octocat/Hello-World/tags", "teams_url": "http://api.example.com/repos/octocat/Hello-World/teams", "trees_url": "http://api.example.com/repos/octocat/Hello-World/git/trees{/sha}", "homepage": "https://example.com", "language": null, "forks_count": 9, "stargazers_count": 80, "watchers_count": 80, "size": 108, "default_branch": "master", "open_issues_count": 0, "has_issues": true, "has_wiki": true, "has_pages": false, "has_downloads": true, "pushed_at": "2011-01-26T19:06:43Z", "created_at": "2011-01-26T19:01:12Z", "updated_at": "2011-01-26T19:14:43Z", "permissions": { "admin": false, "push": false, "pull": true } } Ember London @arkham
  44. Ember London @arkham

  45. GraphQL request Ember London @arkham

  46. mutation { repo: createRepo( name: "Hello-World", description: "This is your

    first example", homepage: "https://example.com", private: false, has_issues: true, has_wiki: true, has_downloads: true ) { id name clone_url user: owner { avatar_url } } } Ember London @arkham
  47. GraphQL response Ember London @arkham

  48. { "data": { repo: { "id": 1296269, "name": "Hello-World", "clone_url":

    "https://example.com/octocat/Hello-World.git", "user": { "avatar_url": "https://example.com/images/error/octocat_happy.gif", } } } } Ember London @arkham
  49. GraphQL ! ISP Ember London @arkham

  50. GraphQL queries allow to create infinite client specific interfaces Ember

    London @arkham
  51. But I don't care about ISP!!! Ember London @arkham

  52. ISP has feelings too... Ember London @arkham

  53. Imagine you have a /articles endpoint. Ember London @arkham

  54. Imagine you have a /articles endpoint. In the frontpage you

    want to display related articles. Ember London @arkham
  55. Imagine you have a /articles endpoint. In the frontpage you

    want to display related articles. Easy, right? Ember London @arkham
  56. Imagine you have a /articles endpoint. In the frontpage you

    want to display related articles. Easy, right? So we just add them to the payload. Ember London @arkham
  57. Imagine you have a /articles endpoint. In the frontpage you

    want to display related articles. Easy, right? So we just add them to the payload. Now every time you call the /articles payload you have to pay the performance price for something you don't really care about. Ember London @arkham
  58. But what if you could do this? Ember London @arkham

  59. { articles { id title excerpt preview_image_url author { name

    } relatedArticles(limit: 5) { title preview_image_url } } } Ember London @arkham
  60. Ember London @arkham

  61. Hmm, okay.. But can I use it in Ember? Ember

    London @arkham
  62. YES github.com/alphasights/ember-graphql-adapter Ember London @arkham

  63. Features 4 Automatic queries generation 4 Field and object aliasing

    4 Async relationships 4 BelongsTo relationships 4 HasMany relationships (sort of) Ember London @arkham
  64. Adapter import { Adapter } from 'ember-graphql-adapter'; export default Adapter.extend({

    endpoint: `${EmberENV.apiBaseUrl}/graph` }); Ember London @arkham
  65. Serializer import { Serializer } from 'ember-graphql-adapter'; export default Serializer.extend({});

    Ember London @arkham
  66. Model DS.Model.extend({ name: DS.attr('string'); }); Ember London @arkham

  67. Route model: function() { return this.store.findAll('company') } Ember London @arkham

  68. Query query { companies { id name } } Ember

    London @arkham
  69. Result { "data": { "companies": [ { id: "1", name:

    "AlphaSights" }, { id: "2", name: "Heroku" } ] } } Ember London @arkham
  70. Ember London @arkham

  71. Ember Data is amazing Ember London @arkham

  72. You can just replace one resource Ember London @arkham

  73. You have no excuses, go and try GraphQL! Ember London

    @arkham
  74. Backend Node github.com/graphql/graphql-js Rails github.com/rmosolgo/graphql-ruby Ember London @arkham

  75. References 4 learngraphql.com 4 facebook.github.io/graphql/ 4 HN thread Ember London

    @arkham
  76. Articles 4 From REST to GraphQL 4 Initial Impressions on

    GraphQL & Relay 4 GraphQL Overview - Getting Started with GraphQL and Node Ember London @arkham
  77. Videos 4 React.js Conf 2015 4 Exploring GraphQL 4 GraphQL

    at The Financial Times Ember London @arkham
  78. Thanks! Questions? Slides @ bit.ly/ember-graph 4 Ju Liu @arkham 4

    engineering.alphasights.com 4 github.com/alphasights/ember-graphql-adapter Ember London @arkham