Advertisement
Advertisement

More Related Content

Similar to JS Fest 2018. Иван Гончаров. W.T.F. is GraphQL?(20)

More from JSFestUA(20)

Advertisement

JS Fest 2018. Иван Гончаров. W.T.F. is GraphQL?

  1. From Back-end to Front-end Kiev 2018 W.T.F. is GraphQL? Ivan Goncharov, APIs.guru
  2. Microsoft: XML-RFC, SOAP, OData Facebook: Thrift, GraphQL Google: gRPC Netflix: Falcorn
  3. What are the problems GraphQL solves?
  4. http://swapi.co/ Now with The Force Awakens data! SWAPI The Star Wars API
  5. GET https://swapi.co/api/people/1/ HTTP/1.0 200 OK Content-Type: application/json { "name": "Luke Skywalker", "height": "172", "mass": "77", "gender": "male", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/2/", ...
  6. https://swapi.co/api/people/1/ SELECT * FROM people WHERE ID = 1
  7. Luke Skywalker Gender: Male | Height: 172cm | Mass: 77kg Homeworld: Tattoine Planetmates: C-3PO Darth Vader Owen Lars R5-D5 Beru Whitesun Iars Biggs Darklighter Shmi Skywlaker Cliegg Lars
  8. https://swapi.co/api/people/1/ { "name": "Luke Skywalker", "height": "172", "mass": "77", "hair_color": "blond", "skin_color": "fair", "eye_color": "blue", "birth_year": "19BBY", "gender": "male", "homeworld": "https://swapi.co/api/planets/1/", "films": [...], "species": [...], ...
  9. https://swapi.co/api/planets/1/ { "name": "Tatooine", "rotation_period": "23", "orbital_period": "304", ... "residents": [ "https://swapi.co/api/people/1/", "https://swapi.co/api/people/2/", "https://swapi.co/api/people/4/", ...
  10. https://swapi.co/api/people/2/ { "name": "C-3PO", "height": "167", "mass": "75", "hair_color": "n/a", "skin_color": "gold", "eye_color": "yellow", "birth_year": "112BBY", "gender": "n/a", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/2/", ...
  11. Problems
  12. { "name": "Luke Skywalker", "height": "172", "mass": "77", "hair_color": "blond", "skin_color": "fair", "eye_color": "blue", "birth_year": "19BBY", "gender": "male", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/2/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/3/", "https://swapi.co/api/films/1/", "https://swapi.co/api/films/7/" ], "species": [ "https://swapi.co/api/species/1/" ], "vehicles": [ "https://swapi.co/api/vehicles/14/", "https://swapi.co/api/vehicles/30/" ], "starships": [ "https://swapi.co/api/starships/12/", "https://swapi.co/api/starships/22/" ], "created": "2014-12-09T13:50:51.644000Z", "edited": "2014-12-20T21:17:56.891000Z", "url": "https://swapi.co/api/people/1/" } { "name": "Tatooine", "rotation_period": "23", "orbital_period": "304", "diameter": "10465", "climate": "arid", "gravity": "1 standard", "terrain": "desert", "surface_water": "1", "population": "200000", "residents": [ "https://swapi.co/api/people/1/", "https://swapi.co/api/people/2/", "https://swapi.co/api/people/4/", "https://swapi.co/api/people/6/", "https://swapi.co/api/people/7/", "https://swapi.co/api/people/8/", "https://swapi.co/api/people/9/", "https://swapi.co/api/people/11/", "https://swapi.co/api/people/43/", "https://swapi.co/api/people/62/" ], "films": [ "https://swapi.co/api/films/5/", "https://swapi.co/api/films/4/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/3/", "https://swapi.co/api/films/1/" ], "created": "2014-12-09T13:50:49.641000Z", "edited": "2014-12-21T20:48:04.175778Z", "url": "https://swapi.co/api/planets/1/" } { "name": "C-3PO", "height": "167", "mass": "75", "hair_color": "n/a", "skin_color": "gold", "eye_color": "yellow", "birth_year": "112BBY", "gender": "n/a", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/2/", "https://swapi.co/api/films/5/", "https://swapi.co/api/films/4/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/3/", "https://swapi.co/api/films/1/" ], "species": [ "https://swapi.co/api/species/2/" ], "vehicles": [], "starships": [], "created": "2014-12-10T15:10:51.357000Z", "edited": "2014-12-20T21:17:50.309000Z", "url": "https://swapi.co/api/people/2/" } { "name": "Darth Vader", "height": "202", "mass": "136", "hair_color": "none", "skin_color": "white", "eye_color": "yellow", "birth_year": "41.9BBY", "gender": "male", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/2/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/3/", "https://swapi.co/api/films/1/" ], "species": [ "https://swapi.co/api/species/1/" ], "vehicles": [], "starships": [ "https://swapi.co/api/starships/13/" ], "created": "2014-12-10T15:18:20.704000Z", "edited": "2014-12-20T21:17:50.313000Z", "url": "https://swapi.co/api/people/4/" } { "name": "Owen Lars", "height": "178", "mass": "120", "hair_color": "brown, grey", "skin_color": "light", "eye_color": "blue", "birth_year": "52BBY", "gender": "male", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/5/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/1/" ], "species": [ "https://swapi.co/api/species/1/" ], "vehicles": [], "starships": [], "created": "2014-12-10T15:52:14.024000Z", "edited": "2014-12-20T21:17:50.317000Z", "url": "https://swapi.co/api/people/6/" } { "name": "Beru Whitesun lars", "height": "165", "mass": "75", "hair_color": "brown", "skin_color": "light", "eye_color": "blue", "birth_year": "47BBY", "gender": "female", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/5/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/1/" ], "species": [ "https://swapi.co/api/species/1/" ], "vehicles": [], "starships": [], "created": "2014-12-10T15:53:41.121000Z", "edited": "2014-12-20T21:17:50.319000Z", "url": "https://swapi.co/api/people/7/" } { "name": "R5-D4", "height": "97", "mass": "32", "hair_color": "n/a", "skin_color": "white, red", "eye_color": "red", "birth_year": "unknown", "gender": "n/a", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/1/" ], "species": [ "https://swapi.co/api/species/2/" ], "vehicles": [], "starships": [], "created": "2014-12-10T15:57:50.959000Z", "edited": "2014-12-20T21:17:50.321000Z", "url": "https://swapi.co/api/people/8/" } { "name": "Biggs Darklighter", "height": "183", "mass": "84", "hair_color": "black", "skin_color": "light", "eye_color": "brown", "birth_year": "24BBY", "gender": "male", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/1/" ], "species": [ "https://swapi.co/api/species/1/" ], "vehicles": [], "starships": [ "https://swapi.co/api/starships/12/" ], "created": "2014-12-10T15:59:50.509000Z", "edited": "2014-12-20T21:17:50.323000Z", "url": "https://swapi.co/api/people/9/" } { "name": "Shmi Skywalker", "height": "163", "mass": "unknown", "hair_color": "black", "skin_color": "fair", "eye_color": "brown", "birth_year": "72BBY", "gender": "female", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/5/", "https://swapi.co/api/films/4/" ], "species": [ "https://swapi.co/api/species/1/" ], "vehicles": [], "starships": [], "created": "2014-12-19T17:57:41.191000Z", "edited": "2014-12-20T21:17:50.401000Z", "url": "https://swapi.co/api/people/43/" } { "name": "Cliegg Lars", "height": "183", "mass": "unknown", "hair_color": "brown", "skin_color": "fair", "eye_color": "blue", "birth_year": "82BBY", "gender": "male", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/5/" ], "species": [ "https://swapi.co/api/species/1/" ], "vehicles": [], "starships": [], "created": "2014-12-20T15:59:03.958000Z", "edited": "2014-12-20T21:17:50.451000Z", "url": "https://swapi.co/api/people/62/" } Overfetching
  13. /people/1/ /planets/1/ /people/*/ x10 ... SELECT * FROM ... SELECT ... x10 ... SELECT * FROM ... Round trips
  14. }); }); }); }); }); }); }); }); }); }); }); }); }); }); }); }); }); }); }); }); }); }); Boilerplate code
  15. Solutions?
  16. /person_profile/1/
  17. Endpoints Explosion https://swapi.co/api/person_profile https://swapi.co/api/person_profile_v2 https://swapi.co/api/person_profile_android https://swapi.co/api/person_profile_ios
  18. /person/1/?include=homeworld.residents &fields[person]=name,gender,height,weight &fields[planet]=name http://jsonapi.org
  19. Structured Query Language Graph GraphQL
  20. https://github.com/facebook/graphq GraphQL Working Draft – October 2016 Introduction This is a Draft RFC Specification for GraphQL, a query language created by Facebook in 2012 for describing the capabilities and requirements of data models for client‐server applications. The development of this standard started in 2015. GraphQL is a new and evolving language and is not complete. Significant enhancement will continue in future editions of this specification.
  21. { "data": { "person": { "name": "C-3PO", "homeworld": { "name": "Tatooine", "residents": [ { "name": "Luke Skywalker", }, { "name": "C-3PO", }, ... ] } } } } Luke Skywalker Gender: Male | Height: 172cm | Mass: 77kg Homeworld: Tattoine Planetmates: C-3PO Darth Vader Owen Lars R5-D5 Beru Whitesun Iars Biggs Darklighter Shmi Skywlaker Cliegg Lars
  22. /people/1/ /planets/1/ /people/*/ x10 ... SELECT * FROM ... SELECT ... x10 ... SELECT * FROM ...
  23. http://swapi.apis.guru/ SELECT * FROM ... SELECT * FROM ... SELECT * FROM ... { person(personID: 1) { name … } } Before: 12 SQL queries After: 3 SQL query
  24. How to call it? 1 const getPerson = swapiFetcher(` 2 query getPerson(id: ID!) { 3 person(personID: $id) { 4 name 5 } 6 } 7 `); 8 9 const result = await getPerson({id: 1}); 10 console.log(result.data); 11 // { person: { name: "Luke Skywalker" } }
  25. 1 function swapiFetcher(query) { 2 return variables => fetch('http://swapi.apis.guru/', { 3 method: 'post', 4 headers: { 'Content-Type': 'application/json' }, 5 body: JSON.stringify({ 6 query, 7 variables 8 }), 9 }).then(response => response.json()); 10 } The most simple SDK
  26. http://bit.ly/relay-vs-apollo ● Caching ● Integration with React, Angular, Vue, ... Relay Apollo
  27. React Apollo HOC 1 function Profile({ data: { person } }) { 2 return ( 3 <div> /* ... */ </div> 4 ); 5 } 6 7 export default graphql(gql ` 8 query getPerson($id: ID) { 9 # ... 10 } 11 `)(Profile);
  28. https://www.howtographql.com/
  29. “GraphQL is unapologetically driven by the requirements of views and the front‐end engineers that write them.” – GraphQL specification
  30. type Query { person(personID: ID!): Person } type Person { name: String homeworld: Planet } type Planet { name: String residents: [Person!] } Schema(SDL) { person(personID: 1) { name homeworld { name residents { name } } } } Query
  31. Query result Luke Skywalker Tatooine ....Luke Skywalker Cliegg Lars homeworld residents
  32. NO FORCE REQUIRED!
  33. 1 import * as sqlite from 'sqlite'; 2 import * as express from 'express'; 3 import * as graphqlHTTP from 'express-graphql'; 4 import { buildSchema } from 'graphql'; Dependencies
  34. 78 const db = await sqlite.open('./sw.sqlite3', {Promise}); 79 const app = express(); 80 app.use('/graphql', graphqlHTTP({ 81 schema: buildSchema(SW_SDL), 82 rootValue: new Query(), 83 context: { db }, 84 })); 85 app.listen(8888); GraphQL Server
  35. class Query { person(args, context) { // ... } } class Person { homeworld(args, context) { // ... } } class Planet { residents(args, context) { // ... } } Resolvers type Query { person(personID: ID!): Person } type Person { name: String # ... homeworld: Planet } type Planet { name: String residents: [Person!] } Schema
  36. Root value 28 class Query { 29 async person(args, context) { 30 const row = await context.db.get( 31 'SELECT * FROM person WHERE id = ?', 32 args.personID, 33 ); 34 if (!row) { 35 throw new Error(`Unknown personID`); 36 } 37 return new Person(row); 38 } 39 }
  37. class Query { person(args, context) { // ... } } class Person { homeworld(args, context) { // ... } } class Planet { residents(args, context) { // ... } } SELECT * FROM person WHERE id = $arg.personID SELECT * FROM planets WHERE id = $this.planetID SELECT * FROM person WHERE homeworld = $this.ID
  38. 94 https://github.com/IvanGoncharov/swapi-demohttps://github.com/IvanGoncharov/swapi-demo
  39. ● Work with any data source (SQL, NoSQL, CMS, ...) ● Can join data from multiple sources ● Can be executed in parallel ● You can write them in any languages (if it has library) GraphQL Resolvers
  40. type Person { name: String # ... numberOfVotes: String averageRating: Float } type Mutation { addStars(personID: ID!, numberOfStars: Int!): Person }
  41. { "data": { "addStars": { "name": "Han Solo", "averageRating": 8.1, "numberOfVotes": 18204 } } } mutation { addStars( personID: 14 numberOfStars: 10 ) { name averageRating numberOfVotes } }
  42. GraphQL is just a query language
  43. Maturity Best practices => Partial Server libraries => Basic Cloud => AWS AppSync Client libraries => Apollo/Relay Tooling => Exiting
  44. Why The Future is GraphQL
  45. https://github.com/APIs-guru
  46. Not covered today :( ● Type system features (Interfaces, Unions, …) ● Advance query features (Aliases, Fragments) ● Introspection (Reflection) ● Versioning - you don’t need it ● Subscriptions - Real time notifications (currently only WebSockets) https://graphql.org
  47. Tomorrow 14:05 - 15:00
  48. Questions? http://bit.ly/js-fest-graphql
Advertisement