Skip to content

Commit

Permalink
Add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
rmosolgo committed Aug 8, 2024
1 parent 173b6bc commit fa623aa
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 4 deletions.
9 changes: 9 additions & 0 deletions guides/authorization/authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Schema members have `authorized?` methods which will be called during execution:
- Fields have `#authorized?(object, args, context)` instance methods
- Arguments have `#authorized?(object, arg_value, context)` instance methods
- Mutations and Resolvers have `.authorized?(object, context)` class methods and `#authorized?(args)` instance methods
- Enum values have `#authorized?(context)` instance methods

These methods are called with:

Expand Down Expand Up @@ -90,6 +91,14 @@ For this to work, the base argument class must be {% internal_link "configured w

See mutations/mutation_authorization.html#can-this-user-perform-this-action {% internal_link "Mutation Authorization", "/mutations/mutation_authorization.html#can-this-user-perform-this-action" %}) in the Mutation Guides.

## Enum Value Authorization

{{ "GraphQL::Schema::EnumValue#authorized?" | api_doc }} is called when client input is received and when the schema returns values to the client.

For authorizing input, if a value's `#authorized?` method returns false, then a {{ "GraphQL::UnauthorizedEnumValueError" | api_doc }} is raised. It passed to your schema's `.unauthorized_object` hook, where you can handle it another way if you want.

For authorizing return values, if an outgoing value's `#authorized?` method returns false, then a {{ "GraphQL::Schema::Enum::UnresolvedValueError" | api_doc }} is raised, which crashes the query. In this case, you should modify your field or resolver to _not_ return this value to an unauthorized viewer. (In this case, the error isn't returned to the viewer because the viewer can't do anything about it -- it's a developer-facing issue instead.)

## Handling Unauthorized Objects

By default, GraphQL-Ruby silently replaces unauthorized objects with `nil`, as if they didn't exist. You can customize this behavior by implementing {{ "Schema.unauthorized_object" | api_doc }} in your schema class, for example:
Expand Down
30 changes: 26 additions & 4 deletions lib/graphql/schema/enum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ class Schema
class Enum < GraphQL::Schema::Member
extend GraphQL::Schema::Member::ValidatesInput

# This is raised when either:
#
# - A resolver returns a value which doesn't match any of the enum's configured values;
# - Or, the resolver returns a value which matches a value, but that value's `authorized?` check returns false.
#
# In either case, the field should be modified so that the invalid value isn't returned.
#
# {GraphQL::Schema::Enum} subclasses get their own subclass of this error, so that bug trackers can better show where they came from.
class UnresolvedValueError < GraphQL::Error
def initialize(value:, enum:, context:, authorized:)
fix_message = if authorized == false
Expand All @@ -38,6 +46,8 @@ def initialize(value:, enum:, context:, authorized:)
end
end

# Raised when a {GraphQL::Schema::Enum} is defined to have no values.
# This can also happen when all values return false for `.visible?`.
class MissingValuesError < GraphQL::Error
def initialize(enum_type)
@enum_type = enum_type
Expand All @@ -47,10 +57,10 @@ def initialize(enum_type)

class << self
# Define a value for this enum
# @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
# @param description [String], the GraphQL description for this value, present in documentation
# @param value [Object], the translated Ruby value for this object (defaults to `graphql_name`)
# @param deprecation_reason [String] if this object is deprecated, include a message here
# @option kwargs [String, Symbol] :graphql_name the GraphQL value for this, usually `SCREAMING_CASE`
# @option kwargs [String] :description, the GraphQL description for this value, present in documentation
# @option kwargs [::Object] :value the translated Ruby value for this object (defaults to `graphql_name`)
# @option kwargs [String] :deprecation_reason if this object is deprecated, include a message here
# @return [void]
# @see {Schema::EnumValue} which handles these inputs by default
def value(*args, **kwargs, &block)
Expand Down Expand Up @@ -144,6 +154,12 @@ def validate_non_null_input(value_name, ctx, max_errors: nil)
end
end

# Called by the runtime when a field returns a value to give back to the client.
# This method checks that the incoming {value} matches one of the enum's defined values.
# @param value [Object] Any value matching the values for this enum.
# @param ctx [GraphQL::Query::Context]
# @raise [GraphQL::Schema::Enum::UnresolvedValueError] if {value} doesn't match a configured value or if the matching value isn't authorized.
# @return [String] The GraphQL-ready string for {value}
def coerce_result(value, ctx)
types = ctx.types
all_values = types ? types.enum_values(self) : values.each_value
Expand All @@ -155,6 +171,12 @@ def coerce_result(value, ctx)
end
end

# Called by the runtime with incoming string representations from a query.
# It will match the string to a configured by name or by Ruby value.
# @param value_name [String, Object] A string from a GraphQL query, or a Ruby value matching a `value(..., value: ...)` configuration
# @param ctx [GraphQL::Query::Context]
# @raise [GraphQL::UnauthorizedEnumValueError] if an {EnumValue} matches but returns false for `.authorized?`. Goes to {Schema.unauthorized_object}.
# @return [Object] The Ruby value for the matched {GraphQL::Schema::EnumValue}
def coerce_input(value_name, ctx)
all_values = ctx.types ? ctx.types.enum_values(self) : values.each_value

Expand Down

0 comments on commit fa623aa

Please sign in to comment.