Slide 1

Slide 1 text

No REST for the Wicked Ember London @arkham

Slide 2

Slide 2 text

A gentle introduction to GraphQL Ember London @arkham

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

What's this GraphQL thing? Ember London @arkham

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

GraphQL* * Does not actually require a Graph Ember London @arkham

Slide 7

Slide 7 text

A simple example Ember London @arkham

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Get all users - Query string { users { id, name } } Ember London @arkham

Slide 10

Slide 10 text

Get all users - JSON response { "data": { "users": [ { "id": "1", "name": "Ju" }, { "id": "2", "name": "Will" }, { "id": "3", "name": "Matz" } ] } } Ember London @arkham

Slide 11

Slide 11 text

Get one user - Query string { user(id: 1) { id, name } } Ember London @arkham

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Create a user - Query string mutation { user: createUser( name: "Tom", twitter: "tomdale", country: "USA" ) { id, name } } Ember London @arkham

Slide 14

Slide 14 text

Create a user - JSON response { "data": { "user": { "id": "4", "name": "Tom" } } } Ember London @arkham

Slide 15

Slide 15 text

Error - Query string mutation { user: createUser( twitter: "tomdale", country: "USA" ) { id, name } } Ember London @arkham

Slide 16

Slide 16 text

Error - JSON response { "errors": [ { "message": "Field 'createUser' argument 'name' of type 'String!' is required but not provided." } ] } Ember London @arkham

Slide 17

Slide 17 text

Relationships Relationships Relationships Ember London @arkham

Slide 18

Slide 18 text

Now imagine we have a company table like this one +----+-------------+---------------+ | id | name | city | +----+-------------+---------------+ | 1 | AlphaSights | London | | 2 | Heroku | San Francisco | +----+-------------+---------------+ Ember London @arkham

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Relationships - Query string { user(id: 1) { id, name, company { name } } } Ember London @arkham

Slide 21

Slide 21 text

Relationships - JSON response { "data": { "user": { "id": "1", "name": "Ju", "company": { "name": "AlphaSights" } } } } Ember London @arkham

Slide 22

Slide 22 text

Nested relationships - Query string { user(id: 1) { id, name, company { name employees: users { name } } } } Ember London @arkham

Slide 23

Slide 23 text

Nested relationships - JSON response { "data": { "user": { "id": "1", "name": "Ju", "company": { "name": "AlphaSights", "employees": [ { "name": "Ju" }, { "name": "Will" } ] } } } } Ember London @arkham

Slide 24

Slide 24 text

But why should I use it? Ember London @arkham

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Ember London @arkham

Slide 27

Slide 27 text

No REST for the wicked! Ember London @arkham

Slide 28

Slide 28 text

REST request GET /users/1 Ember London @arkham

Slide 29

Slide 29 text

REST response ??? Ember London @arkham

Slide 30

Slide 30 text

GraphQL request { user(id: 1) { id, name } } Ember London @arkham

Slide 31

Slide 31 text

GraphQL response { "data": { "user": { "id": "1", "name": "Ju" } } } Ember London @arkham

Slide 32

Slide 32 text

What You See Is What You Get Ember London @arkham

Slide 33

Slide 33 text

Every GraphQL query is a contract Ember London @arkham

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

SOLID Ember London @arkham

Slide 36

Slide 36 text

Interface Segregation Principle Ember London @arkham

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

REST request Ember London @arkham

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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": "[email protected]: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

Slide 44

Slide 44 text

Ember London @arkham

Slide 45

Slide 45 text

GraphQL request Ember London @arkham

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

GraphQL response Ember London @arkham

Slide 48

Slide 48 text

{ "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

Slide 49

Slide 49 text

GraphQL ! ISP Ember London @arkham

Slide 50

Slide 50 text

GraphQL queries allow to create infinite client specific interfaces Ember London @arkham

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

ISP has feelings too... Ember London @arkham

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

But what if you could do this? Ember London @arkham

Slide 59

Slide 59 text

{ articles { id title excerpt preview_image_url author { name } relatedArticles(limit: 5) { title preview_image_url } } } Ember London @arkham

Slide 60

Slide 60 text

Ember London @arkham

Slide 61

Slide 61 text

Hmm, okay.. But can I use it in Ember? Ember London @arkham

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

Features 4 Automatic queries generation 4 Field and object aliasing 4 Async relationships 4 BelongsTo relationships 4 HasMany relationships (sort of) Ember London @arkham

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

Serializer import { Serializer } from 'ember-graphql-adapter'; export default Serializer.extend({}); Ember London @arkham

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

Query query { companies { id name } } Ember London @arkham

Slide 69

Slide 69 text

Result { "data": { "companies": [ { id: "1", name: "AlphaSights" }, { id: "2", name: "Heroku" } ] } } Ember London @arkham

Slide 70

Slide 70 text

Ember London @arkham

Slide 71

Slide 71 text

Ember Data is amazing Ember London @arkham

Slide 72

Slide 72 text

You can just replace one resource Ember London @arkham

Slide 73

Slide 73 text

You have no excuses, go and try GraphQL! Ember London @arkham

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

Articles 4 From REST to GraphQL 4 Initial Impressions on GraphQL & Relay 4 GraphQL Overview - Getting Started with GraphQL and Node Ember London @arkham

Slide 77

Slide 77 text

Videos 4 React.js Conf 2015 4 Exploring GraphQL 4 GraphQL at The Financial Times Ember London @arkham

Slide 78

Slide 78 text

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