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

The Prehistory of GraphQL

The Prehistory of GraphQL

GraphQL Finland 2018 closing keynote

Dan Schafer

October 19, 2018
Tweet

More Decks by Dan Schafer

Other Decks in Programming

Transcript

  1. Prehistory of GraphQL Aug ’12 Feb ’12 Prototype Feb ’08

    Creation of 2012-era FB Server Architecture
  2. “How do I implement authorization?” “How do I make my

    server efficient?” “How do I cache my results?”
  3. “How do I implement authorization?” “How do I make my

    server efficient?” “How do I cache my results?”
  4. “How do I implement authorization?” “How do I make my

    server efficient?” “How do I cache my results?” GraphQL addresses
 none of these…
  5. “How do I implement authorization?” “How do I make my

    server efficient?” “How do I cache my results?” …because these were already answered at FB in 2012…
  6. “How do I implement authorization?” “How do I make my

    server efficient?” “How do I cache my results?” …because these are concerns not specific to GraphQL!
  7. Prehistory of GraphQL Aug ’12 Feb ’12 Prototype Feb ’08

    Creation of 2012-era FB Server Architecture
  8. SELECT `users.name` FROM `friends` WHERE `id1` = 1 LEFT JOIN

    `users` as `u2` WHERE `users.bestId` = `u2.id` LEFT JOIN `friends` WHERE `users.id` = `friends.id1` LEFT JOIN `users` as `u3` WHERE `friends.id2 = u3.id` LEFT JOIN `users` as `u4` WHERE `u3.bestId` = `u4.id` query.sql
  9. SELECT `users.name` FROM `friends` WHERE `id1` = 1 LEFT JOIN

    `users` as `u2` WHERE `users.bestId` = `u2.id` LEFT JOIN `friends` WHERE `users.id` = `friends.id1` LEFT JOIN `users` as `u3` WHERE `friends.id2 = u3.id` LEFT JOIN `users` as `u4` WHERE `u3.bestId` = `u4.id` query.sql
  10. GET cu GET u:2 LRANGE fr:1 0 5 GET u:3

    GET u:4 GET u:5 GET u:6 GET u:7 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12 redis.log {i:1 n:Dan bf:2} {i:2 n:Mary} [3,4,5,6,7] {i:3 n:Nick bf:8} {i:4 n:Lee bf:9} {i:5 n:Alex bf:10} {i:6 n:Laney bf:11} {i:7 n:Ola bf:12} {i:8 n:Leslie} {i:9 n:Ash} {i:10 n:Nina} {i:11 n:Turner} {i:12 n:Katie}
  11. GET cu GET u:2 LRANGE fr:1 0 5 GET u:3

    GET u:4 GET u:5 GET u:6 GET u:7 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12
  12. Dan GET cu GET u:2 LRANGE fr:1 0 5 GET

    u:3 GET u:4 GET u:5 GET u:6 GET u:7 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12
  13. Mary Friends Dan GET cu GET u:2 LRANGE fr:1 0

    5 GET u:3 GET u:4 GET u:5 GET u:6 GET u:7 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12
  14. Laney Alex Lee Nick Ola Mary Friends Dan GET cu

    GET u:2 LRANGE fr:1 0 5 GET u:3 GET u:4 GET u:5 GET u:6 GET u:7 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12
  15. Turner Nina Ash Leslie Katie Laney Alex Lee Nick Ola

    Mary Friends Dan GET cu GET u:2 LRANGE fr:1 0 5 GET u:3 GET u:4 GET u:5 GET u:6 GET u:7 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12
  16. Turner Nina Ash Leslie Katie Laney Alex Lee Nick Ola

    Mary Friends Dan GET cu GET u:2 LRANGE fr:1 0 5 GET u:3 GET u:4 GET u:5 GET u:6 GET u:7 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12
  17. Turner Nina Ash Leslie Katie Laney Alex Lee Nick Ola

    Mary Friends Dan GET cu GET u:2 LRANGE fr:1 0 5 MGET u:3 u:4 u:5
 u:6 u:7
 
 
 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12
  18. Turner Nina Ash Leslie Katie Laney Alex Lee Nick Ola

    Mary Friends Dan GET cu GET u:2 LRANGE fr:1 0 5 MGET u:3 u:4 u:5
 u:6 u:7
 
 
 GET u:8 GET u:9 GET u:10 GET u:11 GET u:12
  19. Turner Nina Ash Leslie Katie Laney Alex Lee Nick Ola

    Mary Friends Dan GET cu GET u:2 LRANGE fr:1 0 5 MGET u:3 u:4 u:5
 u:6 u:7
 
 
 MGET u:8 u:9 u:10
 u:11 u:12 
 

  20. Turner Nina Ash Leslie Katie Laney Alex Lee Nick Ola

    Mary Friends Dan GET cu GET u:2 LRANGE fr:1 0 5 MGET u:3 u:4 u:5
 u:6 u:7
 
 
 MGET u:8 u:9 u:10
 u:11 u:12
 
 

  21. GET cu GET u:2 LRANGE fr:1 0 5 MGET u:3

    u:4 u:5
 u:6 u:7 MGET u:8 u:9 u:10
 u:11 u:12 redis.log {i:1 n:Dan bf:2} {i:2 n:Mary} [3,4,5,6,7] {i:3 n:Nick bf:8} {i:4 n:Lee bf:9} {i:5 n:Alex bf:10} {i:6 n:Laney bf:11} {i:7 n:Ola bf:12} {i:8 n:Leslie} {i:9 n:Ash} {i:10 n:Nina} {i:11 n:Turner} {i:12 n:Katie} getCurrentUser(); get(2); getFriends(1); get(3); get(4); get(5); get(6); get(7); get(8); get(9); get(10); get(11); get(12);
  22. GET cu GET u:2 LRANGE fr:1 0 5 MGET u:3

    u:4 u:5
 u:6 u:7 MGET u:8 u:9 u:10
 u:11 u:12 redis.log {i:1 n:Dan bf:2} {i:2 n:Mary} [3,4,5,6,7] {i:3 n:Nick bf:8} {i:4 n:Lee bf:9} {i:5 n:Alex bf:10} {i:6 n:Laney bf:11} {i:7 n:Ola bf:12} {i:8 n:Leslie} {i:9 n:Ash} {i:10 n:Nina} {i:11 n:Turner} {i:12 n:Katie} getCurrentUser(); DISPATCH() get(2); getFriends(1); DISPATCH() get(3); get(4); get(5); get(6); get(7); DISPATCH() get(8); get(9); get(10); get(11); get(12); DISPATCH()
  23. get_current_user(true, $user); memcache_dispatch(); get_user(2, true, $user2); get_friends(1, true, $friends); memcache_dispatch();

    get_user(3, true, $user3); get_user(4, true, $user4); get_user(5, true, $user5); get_user(6, true, $user6); get_user(7, true, $user7); memcache_dispatch(); get_user(8, true, $user8); get_user(9, true, $user9); get_user(10, true, $user10); get_user(11, true, $user11); get_user(12, true, $user12); memcache_dispatch();
  24. class MyPreparable extends Preparable { $some_data = null; $other_data =

    null; public function prepare($pass) { switch ($pass) { case 0: fetch_some_data($this->some_data) return true; case 1: fetch_other_data($this->some_data, $this->other_data) return false; } public function getData() { return $this->other_data; } } https://www.quora.com/Facebook-Infrastructure-What-are-preparables-and-how-are-they-implemented
  25. class MyPreparable extends Preparable { $some_data = null; $other_data =

    null; public function prepare($pass) { switch ($pass) { case 0: fetch_some_data($this->some_data) return true; case 1: fetch_other_data($this->some_data, $this->other_data) return false; } public function getData() { return $this->other_data; } } https://www.quora.com/Facebook-Infrastructure-What-are-preparables-and-how-are-they-implemented
  26. class MyPreparable extends Preparable { $some_data = null; $other_data =

    null; public function prepare($pass) { switch ($pass) { case 0: fetch_some_data($this->some_data) return true; case 1: fetch_other_data($this->some_data, $this->other_data) return false; } public function getData() { return $this->other_data; } } https://www.quora.com/Facebook-Infrastructure-What-are-preparables-and-how-are-they-implemented
  27. GET cu GET u:2 LRANGE fr:1 0 5 MGET u:3

    u:4 u:5
 u:6 u:7 MGET u:8 u:9 u:10
 u:11 u:12 redis.log {i:1 n:Dan bf:2} {i:2 n:Mary} [3,4,5,6,7] {i:3 n:Nick bf:8} {i:4 n:Lee bf:9} {i:5 n:Alex bf:10} {i:6 n:Laney bf:11} {i:7 n:Ola bf:12} {i:8 n:Leslie} {i:9 n:Ash} {i:10 n:Nina} {i:11 n:Turner} {i:12 n:Katie} getCurrentUser(); get(2); getFriends(1); get(3); get(4); get(5); get(6); get(7); get(8); get(9); get(10); get(11); get(12);
  28. GET cu GET u:2 LRANGE fr:1 0 5 MGET u:3

    u:4 u:5
 u:6 u:7 MGET u:8 u:9 u:10
 u:11 u:12 redis.log {i:1 n:Dan bf:2} {i:2 n:Mary} [3,4,5,6,7] {i:3 n:Nick bf:8} {i:4 n:Lee bf:9} {i:5 n:Alex bf:10} {i:6 n:Laney bf:11} {i:7 n:Ola bf:12} {i:8 n:Leslie} {i:9 n:Ash} {i:10 n:Nina} {i:11 n:Turner} {i:12 n:Katie} await genCurrentUser(); await Promise.all( gen(2), genFriends(1) ); await Promise.all( [3,4,5,6,7].map(x => gen(x)) ); await Promise.all( [8,9,10,11,12].map(x => gen(x)) );
  29. “How do I implement authorization?” “How do I make my

    server efficient?” “How do I cache my results?”
  30. “How do I implement authorization?” “How do I make my

    server efficient?” “How do I cache my results?” Always want to get
 these things right
  31. “How do I implement authorization?” “How do I make my

    server efficient?” “How do I cache my results?” Only want to write
 them once!
  32. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} }
  33. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} }
  34. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> { const data = await genUserFromDb(id); if (!data) { return null; } const canSee = await genCanViewerSeeUser(viewer, data); if (!canSee) { return null; } return new SmartUser(viewer, id, data); } }
  35. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} }
  36. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} }
  37. class SmartUser { genBestFriend(): Promise<?SmartUser> { return SmartUser.gen(this.viewer, this.data.bestFriendId); }

    genProfilePhoto(): Promise<?SmartPhoto> { return SmartPhoto.gen(this.viewer, this.data.profilePhotoId); } }
  38. class SmartUser { static gen(viewer: Viewer, id: string): Promise<?SmartUser> genBestFriend():

    Promise<?SmartUser> genProfilePhoto(): Promise<?SmartPhoto> }
  39. function getBestFriendsProfilePhoto( viewer: Viewer, id: string ): Promise<?SmartPhoto> { const

    user = await SmartUser.gen(viewer, id); if (user == null) { return null; } const bestFriend = await user.genBestFriend(); if (bestFriend == null) { return null; } return await bestFriend.genProfilePhoto(); } class SmartUser { static gen(viewer: Viewer, id: string): Promise<?SmartUser> genBestFriend(): Promise<?SmartUser> genProfilePhoto(): Promise<?SmartPhoto> }
  40. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} }
  41. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} }
  42. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} } GraphQL Object Type!
  43. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} } GraphQL Fields!
  44. class SmartUser { static gen( viewer: Viewer, id: string ):

    Promise<?SmartUser> {} getID(): string {} getName(): string {} genBestFriend(): Promise<?SmartUser> {} genProfilePhoto(): Promise<?SmartPhoto> {} } GraphQL Root Field
 (a.k.a. a field on Query)