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

GraphQL introduction

GraphQL introduction

Introduction to GraphQL presented in FED's forum at eXelate

Ofer Itzhaki

January 30, 2017
Tweet

More Decks by Ofer Itzhaki

Other Decks in Technology

Transcript

  1. Football Fantasy App oferitz rank: 12 total points: 86 100

    April MayJuneJuly Team 1 Team 2 Team 3 Team 4 Player 1 Team 5 rank points rank points rank points rank points rank points Player 2 Player 3 Player 4 Player 5 Player 6 Player 7 Player 8 Player 9 Player 10 Player 12 Player 13
  2. <User user={user} /> <div> <img src={user.avatar} /> <span>{user.name} </span> <UserStats

    stats={user.stats} /> {user.teams.map( team => <Team team={team} /> )} {user.teams.players.map( player => <Player player={player} /> )} </div> Render our user screen
  3. REST API Fetch data - RESTful API GET /users/1/teams GET

    /users/1 GET /users/1/teams/players
  4. REST API or Fetch data - RESTful API GET /users/1/teams

    GET /users/1 GET /users/1/teams/players
  5. REST API or Fetch data - RESTful API GET /users/1/teams

    GET /users/1 GET /users/1?include=teams,players GET /users/1/teams/players
  6. Problems • 3 API calls for 1 component • Overfetching

    of data • How does the data structure looks like?
  7. Problems • 3 API calls for 1 component • Overfetching

    of data • How does the data structure looks like? • API versioning
  8. Problems • 3 API calls for 1 component • Overfetching

    of data • How does the data structure looks like? • API versioning • Ad Hoc endpoints
  9. • Client-specified queries - allows clients to request just what

    they need • Strongly-typed schema - describe all the data • Introspective - allows clients to see what data is available (auto documentation, code generation, static validation, IDE integration) A DECLARATIVE QUERY LANGUAGE FOR API’S created by Facebook in 2012 OS in 2015
  10. { user (id: 1) { avatar username } } {

    "data": { "user": { "avatar": “https: //cdn.com/u/1.jpg“, "username": "oferitz" } } } POST /graph
  11. type Query { user: User team: Team player: Player }

    type User { id: ID! name: String email: String username: String points: Int avatar: String teams: [Team] } type Team { id: ID! name: String crest: String formation: String value: Int budget: Int players: [Player] user: User } type Player { id: ID! name: String position: Positions club: String price: Int image: Int matches: Int goals: Int assists: Int yellowCards: Int redCards: Int goalsConceded: Int }
  12. Server response steps { user (id: 1) { avatar name

    teams { name players { name } } } }
  13. Server response steps Parse String —> AST { user (id:

    1) { avatar name teams { name players { name } } } }
  14. Server response steps Parse String —> AST Validate validate against

    schema { user (id: 1) { avatar name teams { name players { name } } } }
  15. Server response steps Parse String —> AST Validate validate against

    schema Execute resolvers { user (id: 1) { avatar name teams { name players { name } } } }
  16. Query User Team Player user (id: 1) { id, name,

    avatar, teams } avatar name teams { id, name, players }, name name player player { id, name } { id, name } name name { id, name, players }
  17. Query User Team Player user (id: 1) { id, name,

    avatar, teams } avatar name teams { id, name, players }, name name player player { id, name } { id, name } name name { id, name, players }
  18. Query User Team Player user (id: 1) { id, name,

    avatar, teams } avatar name teams { id, name, players }, name name player player { id, name } { id, name } name name { id, name, players } resolvers Execution starts at the top. Resolve functions at the same level are executed concurrently.
  19. Fragments { messi: player(name: “messi”) { …playerFields } ronaldo: player(name:

    “ronaldo”) { …playerFields } } fragment playerFields on Player { name goals assits }
  20. But wait, there's more! Directives @include(if: Boolean) Only include this

    field in the result if the argument is true. @skip(if: Boolean) Skip this field if the argument is true. query dynamic_team($tid: ID!) { team(teamId: $tid) { name players @include(if: $withPlayers) { name } } } { "tid": 1 "withPlayers": true } Unions union Searchable = User | Team | Player type Query { search(text: String!): [Searchable]! } query { search(text: "ro") { ... on User { name } ... on Team { name } ... on Player { name } } } Interfaces interface Searchable { searchText: String! } type User implements Searchable { searchText: String! … } type Team implements Searchable { searchText: String! … } type Player implements Searchable { searchText: String! … } type Query { search(text: String!): [Searchable]! }
  21. But wait, there's more! Directives @include(if: Boolean) Only include this

    field in the result if the argument is true. @skip(if: Boolean) Skip this field if the argument is true. query dynamic_team($tid: ID!) { team(teamId: $tid) { name players @include(if: $withPlayers) { name } } } { "tid": 1 "withPlayers": true } Unions union Searchable = User | Team | Player type Query { search(text: String!): [Searchable]! } query { search(text: "ro") { ... on User { name } ... on Team { name } ... on Player { name } } } Interfaces interface Searchable { searchText: String! } type User implements Searchable { searchText: String! … } type Team implements Searchable { searchText: String! … } type Player implements Searchable { searchText: String! … } type Query { search(text: String!): [Searchable]! }
  22. But wait, there's more! Directives @include(if: Boolean) Only include this

    field in the result if the argument is true. @skip(if: Boolean) Skip this field if the argument is true. query dynamic_team($tid: ID!) { team(teamId: $tid) { name players @include(if: $withPlayers) { name } } } { "tid": 1 "withPlayers": true } Unions union Searchable = User | Team | Player type Query { search(text: String!): [Searchable]! } query { search(text: "ro") { ... on User { name } ... on Team { name } ... on Player { name } } } Interfaces interface Searchable { searchText: String! } type User implements Searchable { searchText: String! … } type Team implements Searchable { searchText: String! … } type Player implements Searchable { searchText: String! … } type Query { search(text: String!): [Searchable]! }
  23. Dataloader batching & caching getPlayersUsingTeamId() teamIds Promise.resolve([players]) single query to

    fetch players for a list of team IDs const PlayerByTeamIdLoader = new DataLoader(getPlayersUsingTeamId) PlayerByTeamIdLoader(1)
  24. Future Live Subscriptions Stream & Defer { user (id: 1)

    { avatar name teams @stream { name players @defer { name } } } } subscription teams { createTeam { name user } } { all_players { avatar name points @live } }
  25. Future Live Subscriptions Stream & Defer { user (id: 1)

    { avatar name teams @stream { name players @defer { name } } } } subscription teams { createTeam { name user } } { all_players { avatar name points @live } }
  26. Future Live Subscriptions Stream & Defer { user (id: 1)

    { avatar name teams @stream { name players @defer { name } } } } subscription teams { createTeam { name user } } { all_players { avatar name points @live } }