dataloadgen-example

command module
v0.0.0-...-59ea8a7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 3, 2024 License: MIT Imports: 9 Imported by: 0

README

dataloadgen-example

This is an example of how to use vikstrous/dataloadgen with gqlgen to improve graphql performance by batching and caching requests to the underlying storage system.

This example was created by following the official tutorial. After completing the tutorial, an example in-memory storage package was created and a loader was created for the User object.

This file listing highlights the important files to look at to understand how loaders can be used with gqlgen.

.
├── gqlgen.yml
├── graph
│   ├── generated.go
│   ├── loader
│   │   └── loader.go - the implementation of loaders
│   ├── model
│   │   ├── models_gen.go
│   │   └── todo.go
│   ├── resolver.go
│   ├── schema.graphqls
│   ├── schema.resolvers.go - the implementation of resolvers that use loaders
│   └── storage
│       └── storage.go - the underlying storage system with artificial delays and logging
├── server.go - the wiring of the stoage system, loaders middleware and resolvers
└── tools.go

To use a loader, the recommended pattern is to create a new one for every HTTP request and inject it into the context using a middleware. server.go contains the wiring for this. Note the call to loader.Middleware. That allows resolvers to access the loader using loader.Get(ctx) and then call the methods on the loader objects.

Try it out

Start the server by running:

go run .

Go to http://localhost:8080 and execute the following query to populate the TODOs:

mutation {
  t1: createTodo(input:{text:"todo1",userId:"alice"}){
    id
    text
    done
    user{
      id
      name
    }
  }
  t2: createTodo(input:{text:"todo2",userId:"alice"}){
    id
    text
    done
    user{
      id
      name
    }
  }
  t3: createTodo(input:{text:"todo3",userId:"bob"}){
    id
    text
    done
    user{
      id
      name
    }
  }
}

The response should look like:

{
  "data": {
    "t1": {
      "id": "9014147064985197323",
      "text": "todo1",
      "done": false,
      "user": {
        "id": "alice",
        "name": "Alice"
      }
    },
    "t2": {
      "id": "763913058984159819",
      "text": "todo2",
      "done": false,
      "user": {
        "id": "alice",
        "name": "Alice"
      }
    },
    "t3": {
      "id": "5828640345075959780",
      "text": "todo3",
      "done": false,
      "user": {
        "id": "bob",
        "name": "Bob"
      }
    }
  }
}

It intentionally takes several seconds to execute the mutations. Every access to the storage package is artificially delayed by a second and accesses are logged to stdout. The output in the console after running this query should look like:

UserStorage.Get
TodoStorage.Put
UserStorage.Get
TodoStorage.Put
UserStorage.Get
TodoStorage.Put

Note that there are only three calls to UserStorage.Get even though the user is fetched both in the execution of the mutation and later in the query for the user. This is because, in the root resolver, after accessing the user storage, the data loader cache is primed. See schema.resolvers.go mutationResolver.CreateTodo() for how the cache is primed.

Now make another, read-only query to fetch all the todos along with their associated users.

{
  todos{
    id
    text
    done
    user{
      id
      name
    }
  }
}

The response should look like:

{
  "data": {
    "todos": [
      {
        "id": "9014147064985197323",
        "text": "todo1",
        "done": false,
        "user": {
          "id": "alice",
          "name": "Alice"
        }
      },
      {
        "id": "763913058984159819",
        "text": "todo2",
        "done": false,
        "user": {
          "id": "alice",
          "name": "Alice"
        }
      },
      {
        "id": "5828640345075959780",
        "text": "todo3",
        "done": false,
        "user": {
          "id": "bob",
          "name": "Bob"
        }
      }
    ]
  }
}

The output in the console should look like:

TodoStorage.GetAll
UserStorage.GetMulti 2

There is no call to UserStorage.Get in this case. The use of a loader in schema.resolvers.go in todoResolver.User() causes concurrent executions to be batched, deduplicated and cached, so only a single call to GetMulti is made instead and only with 2 user IDs.

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL