88use GraphQL \Error \DebugFlag ;
99use GraphQL \Server \ServerConfig ;
1010use GraphQL \Type \Schema ;
11+ use GraphQL \Validator \DocumentValidator ;
12+ use GraphQL \Validator \Rules \QueryComplexity ;
13+ use GraphQL \Validator \Rules \ValidationRule ;
1114use Laminas \Diactoros \ResponseFactory ;
1215use Laminas \Diactoros \StreamFactory ;
1316use Psr \Http \Message \ResponseFactoryInterface ;
2124use TheCodingMachine \GraphQLite \Server \PersistedQuery \NotSupportedPersistedQueryLoader ;
2225
2326use function class_exists ;
27+ use function is_callable ;
2428
2529/**
2630 * A factory generating a PSR-15 middleware tailored for GraphQLite.
@@ -38,6 +42,9 @@ class Psr15GraphQLMiddlewareBuilder
3842
3943 private HttpCodeDeciderInterface $ httpCodeDecider ;
4044
45+ /** @var ValidationRule[] */
46+ private array $ addedValidationRules = [];
47+
4148 public function __construct (Schema $ schema )
4249 {
4350 $ this ->config = new ServerConfig ();
@@ -97,6 +104,18 @@ public function useAutomaticPersistedQueries(CacheInterface $cache, DateInterval
97104 return $ this ;
98105 }
99106
107+ public function limitQueryComplexity (int $ complexity ): self
108+ {
109+ return $ this ->addValidationRule (new QueryComplexity ($ complexity ));
110+ }
111+
112+ public function addValidationRule (ValidationRule $ rule ): self
113+ {
114+ $ this ->addedValidationRules [] = $ rule ;
115+
116+ return $ this ;
117+ }
118+
100119 public function createMiddleware (): MiddlewareInterface
101120 {
102121 if ($ this ->responseFactory === null && ! class_exists (ResponseFactory::class)) {
@@ -109,6 +128,21 @@ public function createMiddleware(): MiddlewareInterface
109128 }
110129 $ this ->streamFactory = $ this ->streamFactory ?: new StreamFactory ();
111130
131+ // If getValidationRules() is null in the config, DocumentValidator will default to DocumentValidator::allRules().
132+ // So if we only added given rule, all of the default rules would not be validated, so we must also provide them.
133+ $ originalValidationRules = $ this ->config ->getValidationRules () ?? DocumentValidator::allRules ();
134+
135+ $ this ->config ->setValidationRules (function (...$ args ) use ($ originalValidationRules ) {
136+ if (is_callable ($ originalValidationRules )) {
137+ $ originalValidationRules = $ originalValidationRules (...$ args );
138+ }
139+
140+ return [
141+ ...$ originalValidationRules ,
142+ ...$ this ->addedValidationRules ,
143+ ];
144+ });
145+
112146 return new WebonyxGraphqlMiddleware ($ this ->config , $ this ->responseFactory , $ this ->streamFactory , $ this ->httpCodeDecider , $ this ->url );
113147 }
114148}
0 commit comments