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.

Better APIs with GraphQL

623 views

Published on

An introduction to GraphQL presented at the first Melbourne GraphQL meetup

Published in: Software
  • Be the first to comment

Better APIs with GraphQL

  1. 1. Better APIs with GraphQL Josh Price github.com/joshprice @joshprice
  2. 2. Agenda • Understand GraphQL and why you'd use it • Build a simple schema • Run queries against the schema • Understand important GraphQL concepts • Summarise client options
  3. 3. REST APIs
  4. 4. REST is great
  5. 5. REST is hard
  6. 6. Cargo Cults
  7. 7. Common Problems Overfetching Underfetching
  8. 8. Internal APIs have strong contracts between client and server
  9. 9. GraphQL
  10. 10. What is GraphQL? • Language for defining schemas, types & queries • Developed by Facebook in 2012 • Used to improve mobile app performance • Serves 300 billion+ requests per day
  11. 11. Open Source • Open sourced in July 2015 • Specification • facebook.github.io/graphql • Reference Implementation • github.com/graphql/graphql-js • Relay released in August 2015
  12. 12. GraphQL Server Implementations • JavaScript reference • Ruby / Python / PHP • Java / Scala (Sangria) • .NET • Elixir / Go / Haskell / OCaml • etc...
  13. 13. GraphQL Misconceptions • Not really about "graphs" • A specification for client/server interaction • Language independent • Assumes nothing about: • transport • message protocol • data store
  14. 14. Exhibit A: REST API Fetch user name and friends names with 2 requests GET /users/1 GET /users/1/friends or a single request GET /users/1/friends?include=user.name,friend.name
  15. 15. Exhibit B: GraphQL API { "data": { user(id: 1) { "user": { name "name": "Josh", friends(first: 1) { "friends": [{ name "name": "James" } }] } } } }
  16. 16. Better Mental Model
  17. 17. Strongly typed
  18. 18. Single Endpoint
  19. 19. Single Unambiguous Query
  20. 20. Consumer Driven Contracts
  21. 21. Less Versioning
  22. 22. Self Documenting
  23. 23. Performance
  24. 24. Let's build our first Schema
  25. 25. Query and Mutation Roots type Query { me: User user(id: Int): User } type Mutation { createPost(title: String!): Post createComment(message: String!): Comment }
  26. 26. Object Types and Enums type User { name: String profilePicture(size: Int = 50): ProfilePicture friends(first: Int, orderBy: FriendOrder): [User] } enum FriendOrder { FIRST_NAME, LAST_NAME, IMPORTANCE }
  27. 27. More Types type ProfilePicture { width: Int height: Int url: String } type Event { name: String attendees(first: Int): [User] }
  28. 28. Simplest Query { me { name } } { "data": { "me": { "name": "Josh Price" } } }
  29. 29. Deeply Nested Query { { me { "data": { name "name": "Josh Price", profilePicture { "profilePicture": { url "url": "http://cdn/josh_50x50.png" } }, friends(first: 1) { "friends": [{ name "name": "James Sadler" } }], events(first: 1) { "events": [{ name "name": "Afterparty!", attendees(first: 1) { "attendees": [{ name "name": "Jenny Savage" } }] } }] } } } }
  30. 30. How do we fetch data?
  31. 31. Resolvers • Your own functions • Could use in memory data • Call any data store • Proxy REST APIs • Call existing services • GraphQL doesn't care • Resolver "Middleware" is possible (Auth, Logging, etc)
  32. 32. User Type with JS Resolvers new GraphQLObject({ type: "User", fields: { name(user) { return user.name }, profilePicture(user, {size}) { return getProfilePicForUser(user, size); }, friends(user) { return user.friendIDs.map(id => getUser(id)); } } });
  33. 33. Mutations Modify Data mutation { acceptFriendRequest(userId: 345124) { user { friends { count } } } } mutation { rsvpToEvent(eventId: 134624, status: ATTENDING) { event { invitees { count } attendees { count } } } }
  34. 34. Setup GraphQL Express import { Schema } from './schema.js'; import graphqlHTTP from 'express-graphql'; import express from 'express'; const app = express(); app.get('/', function(req, res) { res.redirect('/graphql'); }); app.use('/graphql', graphqlHTTP({ schema: Schema, graphiql: true })); app.listen(3000);
  35. 35. Relay • Each view component declares query fragment • Relay batches all data req'ts for render tree • Sends single query • Handles caching using global IDs • Relies on schema conventions for metadata
  36. 36. Client-Side Alternatives • ApolloStack Client • React + Native • Angular 2 • Redux support • Lokka • Simple
  37. 37. Gotchas • Arbitrary Queries • Could be slow if deeply nested (friends of friends...) • Complexity analysis • Query depth • Batching resolvers • Data Loader (JS) • GraphQL Batch (Ruby)
  38. 38. When to use? • Use for internal APIs first, or limited external use • Improve mobile (and desktop performance) • Github has exposed their API externally • Be careful exposing this to the world! • Don't allow arbitrary queries from unknown clients
  39. 39. GraphQL Ecosystem Evolving Quickly
  40. 40. GraphQL Backend as a Service • reindex.io • graph.cool • scaphold.io
  41. 41. Future - GraphQL Spec • Push: Apps should reflect current state of world • Subscriptions + Reactive Backend + RethinkDB • Defer • Stream • Live queries • GraphQL CATS
  42. 42. Subscriptions subscription { createCommentSubscribe(storyId: $id) { comment { ...FBCommentFragment } } }
  43. 43. Warning! Experimental
  44. 44. Defer Directive { { feed { "feed": { stories { "stories": [{ author { name } "author": { "name": "Lee Byron" }, title "title": "GraphQL is the Future" comments @defer { }, { author { name } "author": { "name": "Josh Price" }, comment "title": "REST is old school" } }] } } } } }
  45. 45. Defer - Comments arrive { { feed { "path": ["feed", "stories", 0, "comment"], stories { "data": [{ author { name } "author": { "name": "Joe Bloggs" }, title "comment": "That blew my mind!" comments @defer { }, { author { name } "author": { "name": "Jenny Savage" }, comment "comment": "I love it" } }] } } } }
  46. 46. Stream Directive { { feed { "feed": { stories @stream { "stories": [] author { name } } title } comments @defer { author { name } comment } } } }
  47. 47. Stream - First Story { { feed { "path": ["feed", "stories", 0], stories @stream { "data": [{ author { name } "author": { "name": "Joe Bloggs" }, title "title": "That blew my mind!" comments @defer { }] author { name } } comment } } } }
  48. 48. Live Directive { { feed { "feed": { stories { "stories": [{ author { name } "author": { "name": "Lee Byron" }, title "title": "GraphQL is the Future", likeCount @live "likeCount": 9 } }] } } } }
  49. 49. Live - Likes update on backend { { feed { "path": ["feed", "stories", 0, "likeCount"], stories { "data": 10 author { name } } title likeCount @live } } }
  50. 50. Resources • graphql.org • Github • graphql/graphql-js • graphql/express-graphql • Steve Luscher talk Zero to GraphQL • Awesome GraphQL (chentsulin/awesome-graphql)
  51. 51. Questions?
  52. 52. Thanks!

×