Skip to content

Commit

Permalink
Set up Dataloader to improve database queries via batching
Browse files Browse the repository at this point in the history
  • Loading branch information
denvaar committed Mar 2, 2020
1 parent 1b52398 commit 57a581b
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 40 deletions.
44 changes: 30 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
# AbsintheDemo
# GraphQL server with Dataloader Example

To start your Phoenix server:
I've left a trail of [commit messages](https://github.com/denvaar/absinthe_graphql_dataloader/commits/master) that is hopefully easy to follow. I might try to make a video soon.

* Install dependencies with `mix deps.get`
* Create and migrate your database with `mix ecto.setup`
* Install Node.js dependencies with `cd assets && npm install`
* Start Phoenix endpoint with `mix phx.server`
- [Create a new Phoenix app](https://github.com/denvaar/absinthe_graphql_dataloader/commit/5fa2681f8797aa9317e223437eaf6fbd51e39bfb).
- [Install Absinthe and configure it to work with Phoenix](https://github.com/denvaar/absinthe_graphql_dataloader/commit/51bd434b832091ca394ee2f977bdfe63b5e38ab6).
- [Create a database schema with some basic relations; Hook it up to GraphQL schema](https://github.com/denvaar/absinthe_graphql_dataloader/commit/1b523986f5698eeb7c2dfa8dc12dd357e771d245). At this point we have a naive GraphQL schema. The resolvers cause some horrible database queries to happen.
- [Set up Dataloader with Absinthe to improve performance of database queries](https://github.com/denvaar/absinthe_graphql_dataloader/commit/dbbaae5828ffc1a403ce0cea3bc901e048288e0f).

Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
### Setup Instructions

Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html).
1. Install dependencies `mix deps.get`
1. Create database `mix ecto.setup`
1. Create database schema and populate with data `mix ecto.drop; mix ecto.create; mix ecto.migrate; mix run priv/repo/seeds.exs`
1. Start the Phoenix server `mix phx.server`
1. Run GraphQL queries (and browse schema documentation) from your web browser at `http://localhost:4000/api/graphiql`

## Learn more
### Learn more about Dataloader (Efficiently load data in batches)

* Official website: http://www.phoenixframework.org/
* Guides: https://hexdocs.pm/phoenix/overview.html
* Docs: https://hexdocs.pm/phoenix
* Mailing list: http://groups.google.com/group/phoenix-talk
* Source: https://github.com/phoenixframework/phoenix
- [Elixir Dataloader GitHub repo](https://github.com/absinthe-graphql/dataloader)
- [Elixir Dataloader Hex docs](https://hexdocs.pm/dataloader/Dataloader.html)
- [A helpful blog post](https://schneider.dev/blog/elixir-phoenix-absinthe-graphql-react-apollo-followup/)
- [Original Dataloader JavaScript implementation](https://github.com/graphql/dataloader)

### Learn more about Absinthe (Elixir implementation of GraphQL spec)

- [Absinthe GitHub Repo](https://github.com/absinthe-graphql/absinthe)
- [Absinthe Hex docs](https://hexdocs.pm/absinthe/overview.html)

### Learn more about Phoenix (Elixir Web Framework)

- [Official website](http://www.phoenixframework.org/)
- [Guides](https://hexdocs.pm/phoenix/overview.html)
- [Docs](https://hexdocs.pm/phoenix)
- [Mailing list](http://groups.google.com/group/phoenix-talk)
- [Source](https://github.com/phoenixframework/phoenix)
9 changes: 9 additions & 0 deletions lib/absinthe_demo_web/data_source.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule AbsintheDemo.DataSource do
def data() do
Dataloader.Ecto.new(AbsintheDemo.Repo, query: &query/2)
end

def query(queryable, _params) do
queryable
end
end
12 changes: 12 additions & 0 deletions lib/absinthe_demo_web/graphql/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ defmodule AbsintheDemoWeb.GraphQL.Schema do

alias AbsintheDemoWeb.GraphQL.Resolvers

def context(ctx) do
loader =
Dataloader.new()
|> Dataloader.add_source(:blog_context, AbsintheDemo.DataSource.data())

Map.put(ctx, :loader, loader)
end

def plugins do
[Absinthe.Middleware.Dataloader] ++ Absinthe.Plugin.defaults()
end

query do
@desc "Get all posts"
field :posts, list_of(:post) do
Expand Down
32 changes: 7 additions & 25 deletions lib/absinthe_demo_web/graphql/typedefs.ex
Original file line number Diff line number Diff line change
@@ -1,50 +1,32 @@
defmodule AbsintheDemoWeb.GraphQL.Typedefs do
use Absinthe.Schema.Notation

import Absinthe.Resolution.Helpers, only: [dataloader: 1]

alias AbsintheDemo.Database

object :post do
field :id, :id
field :title, :string
field :body, :string

field :author, :author do
resolve(fn post, _args, _info ->
# Example of N+1 problem
{:ok, Database.get_author(post.author_id)}
end)
end

field :categories, list_of(:category) do
resolve(fn post, _args, _info ->
# Example of N+1 problem
{:ok, Database.get_categories_of_post(post.id)}
end)
end
field :author, :author, resolve: dataloader(:blog_context)

field :categories, list_of(:category), resolve: dataloader(:blog_context)
end

object :author do
field :id, :id
field :name, :string
field :profile_picture_link, :string

field :posts, list_of(:post) do
resolve(fn author, _args, _info ->
# Example of N+1 problem
{:ok, Database.get_posts_of_author(author.id)}
end)
end
field :posts, list_of(:post), resolve: dataloader(:blog_context)
end

object :category do
field :id, :id
field :name, :string

field :posts, list_of(:post) do
resolve(fn category, _args, _info ->
# Example of N+1 problem
{:ok, Database.get_posts_of_category(category.id)}
end)
end
field :posts, list_of(:post), resolve: dataloader(:blog_context)
end
end
3 changes: 2 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ defmodule AbsintheDemo.MixProject do
{:plug_cowboy, "~> 2.0"},
# Absinthe GraphQL stuff
{:absinthe, "~> 1.4.16"},
{:absinthe_phoenix, "~> 1.4.4"}
{:absinthe_phoenix, "~> 1.4.4"},
{:dataloader, "~> 1.0.7"}
]
end

Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
"cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm"},
"dataloader": {:hex, :dataloader, "1.0.7", "58351b335673cf40601429bfed6c11fece6ce7ad169b2ac0f0fe83e716587391", [:mix], [{:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"db_connection": {:hex, :db_connection, "2.2.1", "caee17725495f5129cb7faebde001dc4406796f12a62b8949f4ac69315080566", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"},
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "3.3.4", "95b05c82ae91361475e5491c9f3ac47632f940b3f92ae3988ac1aad04989c5bb", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
Expand Down

0 comments on commit 57a581b

Please sign in to comment.