Skip to content

Instantly share code, notes, and snippets.

@rmosolgo
Last active November 19, 2024 15:06
Show Gist options
  • Save rmosolgo/c3975fcf0fd9df1987320219a82b15fc to your computer and use it in GitHub Desktop.
Save rmosolgo/c3975fcf0fd9df1987320219a82b15fc to your computer and use it in GitHub Desktop.
GraphQL-Ruby async authorization example
require "bundler/inline"
gemfile do
gem "graphql", "2.4.4"
gem "graphql-pro", "1.29.4"
gem "async"
gem "pundit"
end
class ThingPolicy
def initialize(context, object)
@object = object
@context = context
end
def read?
@context.dataloader.with(SleepSource, @object.fetch(:sleep_s)).load(@object.fetch(:name))
end
end
class SleepSource < GraphQL::Dataloader::Source
# IRL this would accept something like a Model class
def initialize(sleep_duration)
@sleep_duration = sleep_duration
end
# IRL this would accept the IDs that could be batched together in an external service call
def fetch(names)
puts "Authorizing #{names.inspect} (#{@sleep_duration})"
sleep @sleep_duration
puts "Finished #{names.inspect}"
# Return a result for each passed-in value:
names.map { true }
end
end
class MySchema < GraphQL::Schema
class BaseObject < GraphQL::Schema::Object
include GraphQL::Pro::PunditIntegration::ObjectIntegration
pundit_role :read
end
class Thing < BaseObject
pundit_policy_class ThingPolicy
field :name, String
end
class Query < BaseObject
pundit_role nil
field :thing_one, Thing, fallback_value: { name: "One", sleep_s: 1 }
field :thing_two, Thing, fallback_value: { name: "Two", sleep_s: 2 }
end
# Pass the whole context as `viewer` so that you can use `context.dataloader`
# see https://graphql-ruby.org/authorization/pundit_integration.html#custom-user-lookup
class Context < GraphQL::Query::Context
def pundit_user
self
end
end
context_class(Context)
query(Query)
use GraphQL::Dataloader::AsyncDataloader
end
pp MySchema.execute("{ thingOne { name } thingTwo { name } }").to_h
# Authorizing ["One"] (1)
# Authorizing ["Two"] (2)
# Finished ["One"]
# Finished ["Two"]
# {"data"=>{"thingOne"=>{"name"=>"One"}, "thingTwo"=>{"name"=>"Two"}}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment