@@ -111,6 +111,10 @@ To work this around:
111111 - [ Adding validation to a mutation] ( #adding-validation-to-a-mutation )
112112 - [ File uploads] ( #file-uploads )
113113 - [ Resolve method] ( #resolve-method )
114+ - [ Resolver middleware] ( #resolver-middleware )
115+ - [ Defining middleware] ( #defining-middleware )
116+ - [ Registering middleware] ( #registering-middleware )
117+ - [ Terminable middleware] ( #terminable-middleware )
114118 - [ Authorization] ( #authorization )
115119 - [ Privacy] ( #privacy )
116120 - [ Query variables] ( #query-variables )
@@ -648,14 +652,14 @@ Note: You can test your file upload implementation using [Altair](https://altair
648652 bodyFormData.set('operationName', null);
649653 bodyFormData.set('map', JSON.stringify({"file":["variables.file"]}));
650654 bodyFormData.append('file', this.file);
651-
655+
652656 // Post the request to GraphQL controller
653657 let res = await axios.post('/graphql', bodyFormData, {
654658 headers: {
655659 "Content-Type": "multipart/form-data"
656660 }
657661 });
658-
662+
659663 if (res.data.status.code == 200) {
660664 // On success file upload
661665 this.file = null;
@@ -765,6 +769,159 @@ class UsersQuery extends Query
765769}
766770```
767771
772+ ### Resolver middleware
773+
774+ #### Defining middleware
775+
776+ To create a new middleware, use the ` make:graphql:middleware ` Artisan command
777+
778+ ``` sh
779+ php artisan make:graphql:middleware ResolvePage
780+ ```
781+
782+ This command will place a new ResolvePage class within your app/GraphQL/Middleware directory.
783+ In this middleware, we will set the Paginator current page to the argument we accept via our ` PaginationType ` :
784+
785+ ``` php
786+ namespace App\GraphQL\Middleware;
787+
788+ use Closure;
789+ use GraphQL\Type\Definition\ResolveInfo;
790+ use Illuminate\Pagination\Paginator;
791+ use Rebing\GraphQL\Support\Middleware;
792+
793+ class ResolvePage extends Middleware
794+ {
795+ public function handle($root, $args, $context, ResolveInfo $info, Closure $next)
796+ {
797+ Paginator::currentPageResolver(function () use ($args) {
798+ return $args['pagination']['page'] ?? 1;
799+ });
800+
801+ return $next($root, $args, $context, $info);
802+ }
803+ }
804+ ```
805+
806+ #### Registering middleware
807+
808+ If you would like to assign middleware to specific queries/mutations,
809+ list the middleware class in the ` $middleware ` property of your query class.
810+
811+ ``` php
812+ namespace App\GraphQL\Queries;
813+
814+ use App\GraphQL\Middleware;
815+ use Rebing\GraphQL\Support\Query;
816+ use Rebing\GraphQL\Support\Query;
817+
818+ class UsersQuery extends Query
819+ {
820+ protected $middleware = [
821+ Middleware\Logstash::class,
822+ Middleware\ResolvePage::class,
823+ ];
824+ }
825+ ```
826+
827+ If you want a middleware to run during every GraphQL query/mutation to your application,
828+ list the middleware class in the ` $middleware ` property of your base query class.
829+
830+ ``` php
831+ namespace App\GraphQL\Queries;
832+
833+ use App\GraphQL\Middleware;
834+ use Rebing\GraphQL\Support\Query as BaseQuery;
835+
836+ abstract class Query extends BaseQuery
837+ {
838+ protected $middleware = [
839+ Middleware\Logstash::class,
840+ Middleware\ResolvePage::class,
841+ ];
842+ }
843+ ```
844+
845+ Alternatively, you can override ` getMiddleware ` to supply your own logic:
846+
847+ ``` php
848+ protected function getMiddleware(): array
849+ {
850+ return array_merge([...], $this->middleware);
851+ }
852+ ```
853+
854+ #### Terminable middleware
855+
856+ Sometimes a middleware may need to do some work after the response has been sent to the browser.
857+ If you define a terminate method on your middleware and your web server is using FastCGI,
858+ the terminate method will automatically be called after the response is sent to the browser:
859+
860+ ``` php
861+ namespace App\GraphQL\Middleware;
862+
863+ use Countable;
864+ use GraphQL\Language\Printer;
865+ use GraphQL\Type\Definition\ResolveInfo;
866+ use Illuminate\Contracts\Pagination\LengthAwarePaginator;
867+ use Illuminate\Pagination\AbstractPaginator;
868+ use Illuminate\Support\Arr;
869+ use Illuminate\Support\Facades\Log;
870+ use Illuminate\Support\Facades\Route;
871+ use Rebing\GraphQL\Support\Middleware;
872+
873+ class Logstash extends Middleware
874+ {
875+ public function terminate($root, $args, $context, ResolveInfo $info, $result): void
876+ {
877+ Log::channel('logstash')->info('', (
878+ collect([
879+ 'query' => $info->fieldName,
880+ 'operation' => $info->operation->name->value ?? null,
881+ 'type' => $info->operation->operation,
882+ 'fields' => array_keys(Arr::dot($info->getFieldSelection($depth = PHP_INT_MAX))),
883+ 'schema' => Arr::first(Route::current()->parameters()) ?? config('graphql.default_schema'),
884+ 'vars' => $this->formatVariableDefinitions($info->operation->variableDefinitions),
885+ ])
886+ ->when($result instanceof Countable, function ($metadata) use ($result) {
887+ return $metadata->put('count', $result->count());
888+ })
889+ ->when($result instanceof AbstractPaginator, function ($metadata) use ($result) {
890+ return $metadata->put('per_page', $result->perPage());
891+ })
892+ ->when($result instanceof LengthAwarePaginator, function ($metadata) use ($result) {
893+ return $metadata->put('total', $result->total());
894+ })
895+ ->merge($this->formatArguments($args))
896+ ->toArray()
897+ ));
898+ }
899+
900+ private function formatArguments(array $args): array
901+ {
902+ return collect(Arr::sanitize($args))
903+ ->mapWithKeys(function ($value, $key) {
904+ return ["\${$key}" => $value];
905+ })
906+ ->toArray();
907+ }
908+
909+ private function formatVariableDefinitions(?iterable $variableDefinitions = []): array
910+ {
911+ return collect($variableDefinitions)
912+ ->map(function ($def) {
913+ return Printer::doPrint($def);
914+ })
915+ ->toArray();
916+ }
917+ }
918+ ```
919+
920+ The terminate method receives both the resolver arguments and the query result.
921+
922+ Once you have defined a terminable middleware, you should add it to the list of
923+ middleware in your queries and mutations.
924+
768925### Authorization
769926
770927For authorization similar to Laravel's Request (or middleware) functionality, we can override the ` authorize() ` function in a Query or Mutation.
@@ -1338,7 +1495,9 @@ class UserType extends GraphQLType
13381495### Pagination
13391496
13401497Pagination will be used, if a query or mutation returns a ` PaginationType ` .
1341- Note that you have to manually handle the limit and page values:
1498+
1499+ Note that unless you use [ resolver middleware] ( #defining-middleware ) ,
1500+ you will have to manually supply both the limit and page values:
13421501
13431502``` php
13441503namespace App\GraphQL\Queries;
0 commit comments