# Argument Directives
Argument directives can be applied to a InputValueDefinition (opens new window).
As arguments may be contained within a list in the schema definition, you must specify what your argument should apply to in addition to its function.
- If it applies to the individual items within the list,
implement the
\Nuwave\Lighthouse\Support\Contracts\ArgDirective
(opens new window) interface. - Else, if it should apply to the whole list,
implement the
\Nuwave\Lighthouse\Support\Contracts\ArgDirectiveForArray
(opens new window) interface.
You must implement exactly one of those two interfaces in order for an argument directive to work.
# ArgTransformerDirective
An \Nuwave\Lighthouse\Support\Contracts\ArgTransformerDirective
(opens new window)
takes an incoming value an returns a new value.
Let's take a look at the built-in @trim directive.
<?php
namespace Nuwave\Lighthouse\Schema\Directives;
use Nuwave\Lighthouse\Support\Contracts\ArgTransformerDirective;
use Nuwave\Lighthouse\Support\Contracts\DefinedDirective;
class TrimDirective extends BaseDirective implements ArgTransformerDirective, DefinedDirective
{
public static function definition(): string
{
return /** @lang GraphQL */ <<<'SDL'
"""
Run the `trim` function on an input value.
"""
directive @trim on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
SDL;
}
/**
* Remove whitespace from the beginning and end of a given input.
*
* @param string $argumentValue
* @return string
*/
public function transform($argumentValue): string
{
return trim($argumentValue);
}
}
The transform
method takes an argument which represents the actual incoming value that is given
to an argument in a query and is expected to transform the value and return it.
For example, if we have the following schema.
type Mutation {
createUser(name: String @trim): User
}
When you resolve the field, the argument will hold the "transformed" value.
<?php
namespace App\GraphQL\Mutations;
use App\User;
class CreateUser
{
public function __invoke($root, array $args): User
{
return User::create([
// This will be the trimmed value of the `name` argument
'name' => $args['name']
]);
}
}
# Evaluation Order
Argument directives are evaluated in the order that they are defined in the schema.
type Mutation {
createUser(
password: String @trim @rules(apply: ["min:10,max:20"]) @hash
): User
}
In the given example, Lighthouse will take the value of the password
argument and:
- Trim any whitespace
- Run validation on it
- Encrypt the password via
bcrypt
# ArgBuilderDirective
An \Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective
(opens new window)
directive allows using arguments passed by the client to dynamically
modify the database query that Lighthouse creates for a field.
Currently, the following directives use the defined filters for resolving the query:
Take the following schema as an example:
type User {
posts(category: String @eq): [Post!]! @hasMany
}
Passing the category
argument will select only the user's posts
where the category
column is equal to the value of the category
argument.
So let's take a look at the built-in @eq directive.
<?php
namespace Nuwave\Lighthouse\Schema\Directives;
use Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective;
use Nuwave\Lighthouse\Support\Contracts\DefinedDirective;
class EqDirective extends BaseDirective implements ArgBuilderDirective, DefinedDirective
{
public static function definition(): string
{
return /** @lang GraphQL */ <<<'SDL'
directive @eq(
"""
Specify the database column to compare.
Only required if database column has a different name than the attribute in your schema.
"""
key: String
) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
SDL;
}
/**
* Apply a "WHERE = $value" clause.
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $builder
* @param mixed $value
* @return \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder
*/
public function handleBuilder($builder, $value)
{
return $builder->where(
$this->directiveArgValue('key', $this->nodeName()),
$value
);
}
}
The handleBuilder
method takes two arguments:
$builder
The query builder for applying the additional query on to.$value
The value of the argument value that @eq was applied on to.
If you want to use a more complex value for manipulating a query,
you can build a ArgBuilderDirective
to work with lists or nested input objects.
Lighthouse's @whereBetween is one example of this.
type Query {
users(createdBetween: DateRange @whereBetween(key: "created_at")): [User!]!
@paginate
}
input DateRange {
from: Date!
to: Date!
}
# ArgResolver
An \Nuwave\Lighthouse\Support\Contracts\ArgResolver
(opens new window)
directive allows you to compose resolvers for complex nested inputs, similar to the way
that field resolvers are composed together.
For an in-depth explanation of the concept of composing arg resolvers, read the explanation of arg resolvers.
# ArgManipulator
An \Nuwave\Lighthouse\Support\Contracts\ArgManipulator
(opens new window)
directive can be used to manipulate the schema AST.
For example, you might want to add a directive that automagically derives the arguments for a field based on an object type. A skeleton for this directive might look something like this:
<?php
namespace App\GraphQL\Directives;
use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
use GraphQL\Language\AST\InputValueDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Support\Contracts\ArgManipulator;
use Nuwave\Lighthouse\Support\Contracts\DefinedDirective;
class ModelArgsDirective extends BaseDirective implements ArgManipulator, DefinedDirective
{
/**
* SDL definition of the directive.
*
* @return string
*/
public static function definition(): string
{
return /** @lang GraphQL */ <<<'SDL'
"""
Automatically generates an input argument based on a type.
"""
directive @typeToInput(
"""
The name of the type to use as the basis for the input type.
"""
name: String!
) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
SDL;
}
/**
* Manipulate the AST.
*
* @param \Nuwave\Lighthouse\Schema\AST\DocumentAST $documentAST
* @param \GraphQL\Language\AST\InputValueDefinitionNode $argDefinition
* @param \GraphQL\Language\AST\FieldDefinitionNode $parentField
* @param \GraphQL\Language\AST\ObjectTypeDefinitionNode $parentType
* @return void
*/
public function manipulateArgDefinition(
DocumentAST &$documentAST,
InputValueDefinitionNode &$argDefinition,
FieldDefinitionNode &$parentField,
ObjectTypeDefinitionNode &$parentType
): void {
$typeName = $this->directiveArgValue('name');
$type = $documentAST->types[$typeName];
$input = $this->generateInputFromType($type);
$argDefinition->name->value = $input->value->name;
$documentAST->setTypeDefinition($input);
}
protected function generateInputFromType(ObjectTypeDefinitionNode $type): InputObjectTypeDefinitionNode
{
// TODO generate this type based on rules and conventions that work for you
}
}