absinthe-resolvers

Guide to implementing efficient and maintainable resolvers in Absinthe.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "absinthe-resolvers" with this command: npx skills add thebushidocollective/han/thebushidocollective-han-absinthe-resolvers

Absinthe - Resolvers

Guide to implementing efficient and maintainable resolvers in Absinthe.

Key Concepts

Basic Resolvers

defmodule MyApp.Resolvers.User do alias MyApp.Accounts

def list_users(_parent, args, _resolution) do {:ok, Accounts.list_users(args)} end

def get_user(_parent, %{id: id}, _resolution) do case Accounts.get_user(id) do nil -> {:error, "User not found"} user -> {:ok, user} end end

def create_user(_parent, %{input: input}, _resolution) do case Accounts.create_user(input) do {:ok, user} -> {:ok, user} {:error, changeset} -> {:error, changeset} end end end

Resolution Context

def current_user(_parent, _args, %{context: %{current_user: user}}) do {:ok, user} end

def current_user(_parent, _args, _resolution) do {:error, "Not authenticated"} end

Dataloader Integration

defmodule MyApp.Schema do use Absinthe.Schema

def context(ctx) do loader = Dataloader.new() |> Dataloader.add_source(MyApp.Repo, Dataloader.Ecto.new(MyApp.Repo))

Map.put(ctx, :loader, loader)

end

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

In type definitions

object :user do field :posts, list_of(:post) do resolve dataloader(MyApp.Repo) end end

Custom Dataloader Source

defmodule MyApp.Loaders.User do def data() do Dataloader.KV.new(&fetch/2) end

defp fetch(:posts_count, user_ids) do counts = MyApp.Posts.count_by_user_ids(user_ids)

Map.new(user_ids, fn id ->
  {id, Map.get(counts, id, 0)}
end)

end end

Best Practices

  • Use Dataloader - Prevents N+1 queries

  • Keep resolvers thin - Delegate to context modules

  • Handle errors gracefully - Return meaningful error messages

  • Use middleware - For cross-cutting concerns like auth

  • Batch related queries - Use dataloader batching

Middleware

defmodule MyApp.Middleware.Auth do @behaviour Absinthe.Middleware

def call(resolution, _config) do case resolution.context do %{current_user: %{}} -> resolution _ -> resolution |> Absinthe.Resolution.put_result({:error, "Unauthorized"}) end end end

Apply to fields

field :admin_data, :string do middleware MyApp.Middleware.Auth resolve &MyApp.Resolvers.Admin.get_data/3 end

Error Handling

defmodule MyApp.Resolvers.Helpers do def handle_changeset_errors(%Ecto.Changeset{} = changeset) do errors = Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> Enum.reduce(opts, msg, fn {key, value}, acc -> String.replace(acc, "%{#{key}}", to_string(value)) end) end)

{:error, errors}

end end

Anti-Patterns

  • Avoid business logic in resolvers

  • Don't query database directly in resolvers

  • Avoid returning raw Ecto changesets

  • Don't skip error handling

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

android-jetpack-compose

No summary provided by upstream source.

Repository SourceNeeds Review
General

fastapi-async-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

storybook-story-writing

No summary provided by upstream source.

Repository SourceNeeds Review
General

atomic-design-fundamentals

No summary provided by upstream source.

Repository SourceNeeds Review