Skip to main content

Validation

Schema Validation

GraphQL Specification

Implements the "Type Validation" sub-sections of the specification's "Type System" section.

Guaranties that the GraphQLSchema instance is valid, verifies the Type System validations in the specification. For example, an Object field's type can only be an Output Type or an Union should have at least one possible type and all of them have to be Object types.

This will be executed before stating a GraphQL server. Leto implements all of the Specification's schema validation. The code for all rules can be found in the validate_schema.dart file in package:leto_schema.

Document Validation

GraphQL Specification

This will be executed before executing any request. Leto implements all of the Specification's document validation. The code for all rules can be found in the validate folder in package:leto_schema.

You can add custom validation rules to a server with the GraphQL.customValidationRules parameter, they will be added on top of the specifiedValidationRules. One example of a custom validation rule is the Query Complexity validation.

Query Complexity

Tests

This document validation rule allows you to restrict the complexity of a GraphQL request.

The provided queryComplexityRuleBuilder returns a ValidationRule that reports errors when the maxComplexity or maxDepth configuration parameters are reached.

  • maxComplexity

Specifies the maximum complexity for a given operation. The complexity is measured based on the selected fields and should be. If this complexity is surpassed (is greater) a validation error will be reported.

  • maxDepth

Specifies the maximum depth for a given operation. The depth is defined as the number of objects (including the root operation object) that have to be traversed to arrive to a given field. If this depth is surpassed (is greater) a validation error will be reported.

The complexity for each fieldNode is given by:

complexity = fieldComplexity + (childrenComplexity + fieldTypeComplexity) * complexityMultiplier

Where fieldComplexity is the ElementComplexity in GraphQLObjectField.attachments or defaultFieldComplexity if there aren't any.

childrenComplexity is:

  • scalar or enum (leaf types): 0
  • object or interface: sum(objectFieldsComplexities)
  • union: max(possibleTypesComplexities)

fieldTypeComplexity will be taken as the ElementComplexity from GraphQLNamedType.attachments or 0 if there aren't any.

If the fieldType is a GraphQLListType, complexityMultiplier will be the provided listComplexityMultiplier, otherwise 1.

Skip validation with Persisted Queries

TODO: 1A

Using the PersistedQueriesExtensions you can set the skipValidation parameter so that the validation is skipped for already cached (and validated) documents.

Input Validation

Input validation refers to the verification of the values or structure of the payload sent as input in a request. It could, of coursed, be performed manually before the execution of each request. However, we provide a couple of tools to help with the process, in particular using code generation and the valida package.

The following example shows an input object ConnectionArguments with the annotations @Valida() and its fields first and last with the annotation @ValidaNum(min: 1). If the ConnectionArguments object is used as input in a resolver, the validation is performed over the input value on execution and an error will be thrown if either first or last are less than 1. For more information on the supported annotations and validations, view the valida package.

()
()
()
class ConnectionArguments {
/// Returns the items in the list that come before the specified cursor.
final String? before;

/// Returns the items in the list that come after the specified cursor.
final String? after;

/// Returns the first n items from the list.
(min: 1)
final int? first;

/// Returns the last n items from the list.
(min: 1)
final int? last;

const ConnectionArguments({
this.before,
this.after,
this.first,
this.last,
});

factory ConnectionArguments.fromJson(Map<String, Object?> json) =>
_$ConnectionArgumentsFromJson(json);

Map<String, Object?> toJson() => _$ConnectionArgumentsToJson(this);
}