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

GraphQL: the good, the bad, the f* cool

GraphQL: the good, the bad, the f* cool

Avatar for Pablo Margreff

Pablo Margreff

August 11, 2020

Other Decks in Programming

Transcript

  1. WHAT GRAPHQL IS? A speci cation for a Graph based

    API Queries - No side effect Mutations - Side effet Subscriptions - Pub/Sub or Noti cations 3
  2. WHAT GRAPHQL HELP US TO ACHIEVE AS A TEAM Fast

    iterations Multi disciplinary teams Documentation for free Centralized logic Descentralized information Made life boring 4
  3. GET https://api.github.com/organizations/github { "login": "github", "id": 1, "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", "url":

    "https://api.github.com/orgs/github", "repos_url": "https://api.github.com/orgs/github/repos", "events_url": "https://api.github.com/orgs/github/events", "hooks_url": "https://api.github.com/orgs/github/hooks", "issues_url": "https://api.github.com/orgs/github/issues", "description": "A great organization", "name": "github", "company": "GitHub", "location": "San Francisco", "email": "[email protected]", "is_verified": true, ... } 7
  4. GET https://api.github.com/orgs/github/repos [ { "id": 1296269, "name": "Hello-World", "full_name": "octocat/Hello-World",

    "private": false, "description": "This your first repo!", "fork": false, "branches_url": "http://api.gthub.com/repos/octocat/Hello-World/branches{/branch} "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", "language": null, "forks_count": 9, "stargazers_count": 80, "pushed_at": "2011-01-26T19:06:43Z", "created_at": "2011-01-26T19:01:12Z", ... } ] 8
  5. 9

  6. EFFICIENCY Underfetch: make a request again, and again... Overfetch: too

    much data 1 MB from SSD: 400us 1 MB from America to Europe: 150ms 10
  7. 11

  8. QUERY { viewer { login bio company } } {

    "data": { "viewer": { "login": "pmargreff", "bio": "I'm the dog, not the human. ", "company": null } } } 12
  9. QUERY WITH ARGUMENT user(login: "josevalim") { { 1 2 name

    3 bio 4 company 5 } 6 } 7 { "data": { "user": { "name": "José Valim", "bio": "Creator of @elixir-lang.", "company": "@dashbitco " } } } 13 . 1
  10. GRAPHQL VS REST { viewer { login bio company }

    } curl https://github.com/api/v3/users/josevalim 13 . 2
  11. REST USER RESPONSE { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=",

    "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false, "name": "monalisa octocat", "company": "GitHub", 13 . 3
  12. QUERY WITH NODES { user(login: "josevalim") { login name repositoriesContributedTo(first:

    3, contributionTypes: ISSUE) { nodes { name languages(first: 2) { nodes { name } } } } } } 14
  13. QUERY WITH MULTIPLE NODES { "data": { "user": { "login":

    "josevalim", "name": "José Valim", "repositoriesContributedTo": { "nodes": [ { "name": "elixir", "languages": { "nodes": [ { "name": "Shell" }, { "name": "PowerShell" } ] } }, 15 . 1
  14. REST 1 - curl https://api.github.com/users/josevalim 2 - curl https://api.github.com/users/josevalim/events/public 3

    - filter issues events 4 - filter repos from issues 5 - sort and get {5} 6 - curl https://api.github.com/repos/elixir/elixir-lang/languages 7 - curl https://api.github.com/repos/erlang/cowboy/languages . . . 15 . 2
  15. { user(login: "josevalim") { name bio company } } 1

    2 3 4 5 6 7 type Query { user(login: String!): User } type User { name: String! bio: String company: String ... } 1 2 3 4 5 6 7 8 9 10 16
  16. user(login: "josevalim") { { 1 2 name 3 bio 4

    company 5 } 6 } 7 user(login: String!): User type Query { 1 2 } 3 4 type User { 5 name: String! 6 bio: String 7 company: String 8 ... 9 } 10 17
  17. name bio company { 1 user(login: "josevalim") { 2 3

    4 5 } 6 } 7 type User { name: String! bio: String company: String ... } type Query { 1 user(login: String!): User 2 } 3 4 5 6 7 8 9 10 18
  18. user(login: String!): User type Query { 1 2 } 3

    query do @desc "Get a user by name" field :user, :user do arg(:login, non_null(:string)) resolve(&Resolvers.User.get_user_by_login/2) end end 1 2 3 4 5 6 7 @desc "Get a user by name" query do 1 2 field :user, :user do 3 arg(:login, non_null(:string)) 4 resolve(&Resolvers.User.get_user_by_login/2) 5 end 6 end 7 arg(:login, non_null(:string)) query do 1 @desc "Get a user by name" 2 field :user, :user do 3 4 resolve(&Resolvers.User.get_user_by_login/2) 5 end 6 end 7 resolve(&Resolvers.User.get_user_by_login/2) query do 1 @desc "Get a user by name" 2 field :user, :user do 3 arg(:login, non_null(:string)) 4 5 end 6 end 7 field :user, :user do query do 1 @desc "Get a user by name" 2 3 arg(:login, non_null(:string)) 4 resolve(&Resolvers.User.get_user_by_login/2) 5 end 6 end 7 20
  19. name: String bio: String company: String login: String! type User

    { 1 2 3 4 5 repositories: [Repository! 6 } 7 repositories: [Repository! type User { 1 name: String 2 bio: String 3 company: String 4 login: String! 5 6 } 7 field :name, :string field :bio, :string field :company, :string field :login, non_null(:string) object :user do 1 2 3 4 5 6 field :repositories, list_of(:repository) do 7 resolve(&Resolvers.User.list_repos/3) 8 end 9 end 10 field :repositories, list_of(:repository) do resolve(&Resolvers.User.list_repos/3) end object :user do 1 field :name, :string 2 field :bio, :string 3 field :company, :string 4 field :login, non_null(:string) 5 6 7 8 9 end 10 21
  20. GRAPHQL AS SERVICE AGGREGATOR def list_repos(%{user_id: user_id}, _args, _resolution) do

    Users.list_repo_by_user(user_id) end 1 2 3 4 def list_repos(%{user_id: user_id}, _args, _resolution) do 5 Repository.Client.list_by_user(user_id) 6 |> Repository.Parser.from_request_to_schema() 7 end 8 9 def list_repos(%{user_id: user_id}, _args, _resolution) do 10 GRPCServer.Repository.get_user(user_id) 11 end 12 def list_repos(%{user_id: user_id}, _args, _resolution) do Repository.Client.list_by_user(user_id) |> Repository.Parser.from_request_to_schema() end def list_repos(%{user_id: user_id}, _args, _resolution) do 1 Users.list_repo_by_user(user_id) 2 end 3 4 5 6 7 8 9 def list_repos(%{user_id: user_id}, _args, _resolution) do 10 GRPCServer.Repository.get_user(user_id) 11 end 12 def list_repos(%{user_id: user_id}, _args, _resolution) do GRPCServer.Repository.get_user(user_id) end def list_repos(%{user_id: user_id}, _args, _resolution) do 1 Users.list_repo_by_user(user_id) 2 end 3 4 def list_repos(%{user_id: user_id}, _args, _resolution) do 5 Repository.Client.list_by_user(user_id) 6 |> Repository.Parser.from_request_to_schema() 7 end 8 9 10 11 12 22
  21. GRAPHQL AS SERVICE AGGREGATOR Umbrella applications (monorepo) Micro-services Lambdas Geodata,

    Search Engines (elasticsearch, algolia, etc) Services (Salesforce, Zendesk, etc) 23
  22. 24

  23. UNSOLVED PROBLEMS Isn't easy to gure out rate limit Test

    granularity Easy to reuse heavy queries Hard to remove elds Schema modeling 25
  24. ADDITIONAL CONTENT The Do’s and Don’ts for your schema and

    GraphQL operations - Apollo GraphQL design tutorial - Shopify 28