Last active
November 19, 2024 15:06
-
-
Save rmosolgo/c3975fcf0fd9df1987320219a82b15fc to your computer and use it in GitHub Desktop.
GraphQL-Ruby async authorization example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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