NAME
GraphQL::Houtou::Directive - Directive definitions for GraphQL::Houtou
SYNOPSIS
use GraphQL::Houtou::Directive;
use GraphQL::Houtou::Schema;
use GraphQL::Houtou::Type::Object;
use GraphQL::Houtou::Type::Scalar qw($Boolean $String);
my $Upper = GraphQL::Houtou::Directive->new(
name => 'upper',
locations => [qw(FIELD FRAGMENT_SPREAD INLINE_FRAGMENT)],
apply_field_result => sub {
my ($value) = @_;
return undef if !defined $value;
return uc $value;
},
);
my $Mask = GraphQL::Houtou::Directive->new(
name => 'mask',
locations => [qw(FIELD FRAGMENT_SPREAD INLINE_FRAGMENT)],
args => {
enabled => { type => $Boolean->non_null },
},
apply_field_result => sub {
my ($value, $source, $field_args, $context, $info, $return_type, $directive_args) = @_;
return $directive_args->{enabled} ? '***' : $value;
},
);
my $RequireRole = GraphQL::Houtou::Directive->new(
name => 'requireRole',
locations => [qw(FIELD_DEFINITION)],
args => {
role => { type => $String->non_null },
},
resolve_field => sub {
my ($next, $source, $field_args, $context, $info, $return_type, $directive_args) = @_;
die "forbidden\n" if (($context || {})->{role} || '') ne ($directive_args->{role} || '');
return $next->();
},
);
my $schema = GraphQL::Houtou::Schema->new(
query => GraphQL::Houtou::Type::Object->new(
name => 'ExampleQuery',
fields => {
hello => {
type => $String,
resolver_mode => 'native',
resolve => sub { 'hello' },
},
secret => {
type => $String,
directives => [
{ name => 'requireRole', arguments => { role => 'admin' } },
],
},
},
),
directives => [
@GraphQL::Houtou::Directive::SPECIFIED_DIRECTIVES,
$Upper,
$Mask,
$RequireRole,
],
);
my $result = $schema->execute(
'query Q($enabled: Boolean!) { hello @upper @mask(enabled: $enabled) secret }',
root_value => { secret => 'classified' },
context => { role => 'admin' },
variables => { enabled => 0 },
);
DESCRIPTION
GraphQL::Houtou::Directive represents a directive definition that can be registered in GraphQL::Houtou::Schema->new(directives => [...]).
Executable directives can be implemented in two ways.
apply_field_resultUse this for directives that transform an already-resolved field value. This is the lighter-weight hook for query directives such as formatting, masking, or string rewriting.
The callback receives:
($value, $source, $field_args, $context, $info, $return_type, $directive_args, $directive)resolve_fieldUse this for middleware-style directives that need to control whether the field resolver runs at all, wrap the default resolver, or short-circuit execution. This is the right hook for
FIELD_DEFINITIONdirectives such as authorization checks.The callback receives:
($next, $source, $field_args, $context, $info, $return_type, $directive_args, $directive)
If both are present, apply_field_result is preferred for executable runtime directives. In practice, apply_field_result should be the default choice for query/fragment directives, and resolve_field should be reserved for true resolver middleware.
For a runnable reference, see examples/custom-directives.pl.