From 999fa1179373928f8418661e6702b8fc175351b5 Mon Sep 17 00:00:00 2001 From: Vivek Date: Mon, 25 Mar 2024 18:05:27 +0530 Subject: [PATCH] Add authorization and response handlers (#5) --- README.md | 36 ++++++++++++++++++++++++---- lib/phantom/graphql.rb | 5 ++++ lib/phantom/graphql/authorization.rb | 23 ++++++++++++++++++ lib/phantom/graphql/response.rb | 15 ++++++++++++ 4 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 lib/phantom/graphql/authorization.rb create mode 100644 lib/phantom/graphql/response.rb diff --git a/README.md b/README.md index 5870c08..b38c703 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,36 @@ ## Graphql -Includes `enum` shorthand, +### Shorthand -```rb -field :status, enum("PersonStatusEnum", Person.statuses.keys), null: false -``` +- Includes `enum` shorthand, + + ```rb + field :status, enum("PersonStatusEnum", Person.statuses.keys), null: false + ``` + +### Response handler + +- Catches errors automatically: + + - `ActiveRecord::RecordNotFound` + +- Includes `raise_error` response handler in `GraphQL::Schema::RelayClassicMutation` + + ```rb + raise_error person.errors.full_messages.to_sentence unless person.update(status: :active) + ``` + +### Authorization + +- Add `authorize` option to `field` + + ```rb + # app/graphql/types/base_field.rb + + field_class.include(Phantom::Graphql::Authorization) + ``` + + ```rb + field :posts, [Types::PostType], authorize: "PostPolicy#index?", null: false + ``` diff --git a/lib/phantom/graphql.rb b/lib/phantom/graphql.rb index 73f2597..2756ed9 100644 --- a/lib/phantom/graphql.rb +++ b/lib/phantom/graphql.rb @@ -5,8 +5,13 @@ module Phantom::Graphql end +require "phantom/graphql/authorization" require "phantom/graphql/enum" +require "phantom/graphql/response" GraphQL::Schema::InputObject.extend(Phantom::Graphql::Enum) GraphQL::Schema::Object.extend(Phantom::Graphql::Enum) GraphQL::Schema::RelayClassicMutation.extend(Phantom::Graphql::Enum) + +GraphQL::Schema.include(Phantom::Graphql::Response::ExceptionsHandler) +GraphQL::Schema::RelayClassicMutation.include(Phantom::Graphql::Response::Helpers) diff --git a/lib/phantom/graphql/authorization.rb b/lib/phantom/graphql/authorization.rb new file mode 100644 index 0000000..da9e170 --- /dev/null +++ b/lib/phantom/graphql/authorization.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Phantom::Graphql::Authorization + class AuthorizeExtension < GraphQL::Schema::FieldExtension + def resolve(context:, object:, arguments:, **_rest) + name, action = options.split("#") + + authorized = name.constantize.new(context[:current_session]).send(action) + + raise GraphQL::ExecutionError, "Unauthorized" unless authorized + + yield object, arguments + end + end + + def initialize(*args, authorize: nil, **kwargs, &block) + extensions = (kwargs[:extensions] ||= []) + + extensions << { Phantom::Graphql::Authorization::AuthorizeExtension => authorize } if authorize.present? + + super(*args, **kwargs, &block) + end +end diff --git a/lib/phantom/graphql/response.rb b/lib/phantom/graphql/response.rb new file mode 100644 index 0000000..97601fe --- /dev/null +++ b/lib/phantom/graphql/response.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Phantom::Graphql::Response + module ExceptionsHandler + def self.included(base) + base.rescue_from(ActiveRecord::RecordNotFound) { |e| raise GraphQL::ExecutionError, "#{e.model} not found" } + end + end + + module Helpers + def raise_error(error) + raise GraphQL::ExecutionError, error + end + end +end