Schema and Document Validation Rules
GraphQL schemas and documents can be validated for potential errors, misconfigurations, bad practices or perhaps restrictions, such as restricting the complexity (how nested and how many fields) of a query. We perform all the document and schema validations in the specification. Most of the code was ported from graphql-js.
You can find the implementation for all the rules in the lib/src/validate/rules
directory.
We also provide a QueryComplexity validation rule.
You can use two functions to validate GraphQL documents, both return a List<GraphQLError>
:
validateDocument(GraphQLSchema, gql.DocumentNode)
You can specify multiple validation rules. The default is specifiedRules
.
validateSDL(gql.DocumentNode, GraphQLSchema?)
If a GraphQLSchema
is passed, it is assumed that the document SDL is an extension over the given schema.
You can specify multiple validation rules. The default is specifiedSDLRules
(../leto_schema/lib/src/validate/validate.dart).
Custom Validations
You can provide custom validations, they are a function that receives a ValidationCtx
and returns a visitor that reports errors thought the context.
For example, the following validation rule checks that argument names are unique:
const _uniqueArgumentNamesSpec = ErrorSpec(
spec: 'https://spec.graphql.org/draft/#sec-Argument-Names',
code: 'uniqueArgumentNames',
);
/// Unique argument names
///
/// A GraphQL field or directive is only valid if all supplied arguments are
/// uniquely named.
///
/// See https://spec.graphql.org/draft/#sec-Argument-Names
Visitor uniqueArgumentNamesRule(
SDLValidationCtx context, // ASTValidationContext,
) {
final visitor = TypedVisitor();
VisitBehavior? checkArgUniqueness(List<ArgumentNode> argumentNodes) {
final seenArgs = argumentNodes.groupListsBy((arg) => arg.name.value);
for (final entry in seenArgs.entries) {
if (entry.value.length > 1) {
context.reportError(
GraphQLError(
'There can be only one argument named "${entry.key}".',
locations: List.of(entry.value
.map((node) => node.name.span!.start)
.map((e) => GraphQLErrorLocation.fromSourceLocation(e))),
extensions: _uniqueArgumentNamesSpec.extensions(),
),
);
}
}
}
visitor.add<FieldNode>((node) => checkArgUniqueness(node.arguments));
visitor.add<DirectiveNode>((node) => checkArgUniqueness(node.arguments));
return visitor;
}