コード例 #1
0
        private static IEnumerable <ValidationError> ValidateGraphQLType <T>(this GraphQLIntrospectionSchema graphQLIntrospectionSchema, GraphQLOperationType operationType, IGraphQLFieldBuilder fieldBuilder)
        {
            if (fieldBuilder is null)
            {
                throw new ArgumentNullException(nameof(fieldBuilder));
            }

            var validator = new GraphQLValidation();

            return(validator.ValidateGraphQLSelectionSet(graphQLIntrospectionSchema, operationType, fieldBuilder.GenerateSelectionSet(typeof(T))));
        }
コード例 #2
0
 /// <summary>
 /// Returns the GraphQLIntrospectionSchema with the implicit fields __schema, __type and __typename which is defined in the GraphQL specification
 /// <see cref="https://graphql.github.io/graphql-spec/June2018/#sec-Schema-Introspection"/>
 /// </summary>
 /// <param name="schema">The schema without the implicit fields</param>
 /// <returns>Returns the GraphQLIntrospectionSchema with the implicit fields __schema, __type and __typename which is defined in the GraphQL specification</returns>
 public static GraphQLIntrospectionSchema WithImplicitFields(this GraphQLIntrospectionSchema schema)
 {
     return(new GraphQLIntrospectionSchema
     {
         QueryType = schema.QueryType,
         MutationType = schema.MutationType,
         SubscriptionType = schema.SubscriptionType,
         Directives = schema.Directives,
         Types = schema.Types.Select(type => GetIntrospectionType(type, schema))
     });
 }
コード例 #3
0
        /// <summary>
        /// Validate if the GraphQL <paramref name="selectionSet"/> is valid for the specified <paramref name="graphQLIntrospectionSchema"/> and <paramref name="operationType"/>
        /// </summary>
        /// <param name="graphQLIntrospectionSchema">The introspectionSchema to validate against</param>
        /// <param name="operationType">The operationType to validate against</param>
        /// <param name="selectionSet">The selectionSet which should be validated</param>
        /// <returns>An empty list if no errors were found or a <see cref="ValidationError"/> for each error found</returns>
        public IEnumerable <ValidationError> ValidateGraphQLSelectionSet(GraphQLIntrospectionSchema graphQLIntrospectionSchema, GraphQLOperationType operationType, IEnumerable <GraphQLField> selectionSet)
        {
            if (graphQLIntrospectionSchema is null)
            {
                throw new ArgumentNullException(nameof(graphQLIntrospectionSchema));
            }

            if (selectionSet is null)
            {
                throw new ArgumentNullException(nameof(selectionSet));
            }

            // Get implicit types
            var graphQLIntrospectionSchemaWithImplicitTypes = graphQLIntrospectionSchema.WithImplicitFields();

            GraphQLIntrospectionFullType type = null;

            switch (operationType)
            {
            case GraphQLOperationType.Query:
                if (graphQLIntrospectionSchemaWithImplicitTypes.QueryType != null)
                {
                    type = GetTypeByName(graphQLIntrospectionSchemaWithImplicitTypes, graphQLIntrospectionSchemaWithImplicitTypes.QueryType.Name);
                }
                break;

            case GraphQLOperationType.Mutation:
                if (graphQLIntrospectionSchemaWithImplicitTypes.MutationType != null)
                {
                    type = GetTypeByName(graphQLIntrospectionSchemaWithImplicitTypes, graphQLIntrospectionSchemaWithImplicitTypes.MutationType.Name);
                }
                break;

            case GraphQLOperationType.Subscription:
                if (graphQLIntrospectionSchemaWithImplicitTypes.SubscriptionType != null)
                {
                    type = GetTypeByName(graphQLIntrospectionSchemaWithImplicitTypes, graphQLIntrospectionSchemaWithImplicitTypes.SubscriptionType.Name);
                }
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(operationType), $"Operationtype {operationType} is not supported");
            }

            if (type == null)
            {
                return(new List <ValidationError> {
                    new ValidationError(ValidationType.Operation_Type_Not_Found, operationType)
                });
            }

            return(ValidateSelectionSet(graphQLIntrospectionSchemaWithImplicitTypes, selectionSet, type, operationType, rootLevel: true));
        }
コード例 #4
0
        private static GraphQLIntrospectionFullType GetSubtype(GraphQLIntrospectionSchema graphQLIntrospectionSchema, GraphQLIntrospectionTypeRef graphQLIntrospectionTypeRef)
        {
            if (graphQLIntrospectionSchema is null)
            {
                throw new ArgumentNullException(nameof(graphQLIntrospectionSchema));
            }

            if (graphQLIntrospectionTypeRef is null)
            {
                throw new ArgumentNullException(nameof(graphQLIntrospectionTypeRef));
            }

            if (HasSubtype(graphQLIntrospectionTypeRef.Kind))
            {
                return(GetSubtype(graphQLIntrospectionSchema, graphQLIntrospectionTypeRef.OfType));
            }

            return(GetTypeByName(graphQLIntrospectionSchema, graphQLIntrospectionTypeRef.Name));
        }
コード例 #5
0
 /// <summary>
 /// Validate if the GraphQL query type <typeparamref name="T"/> is valid for the specified <paramref name="graphQLIntrospectionSchema"/> and <paramref name="operationType"/>
 /// </summary>
 /// <typeparam name="T">The GraphQL query type to validate against</typeparam>
 /// <param name="graphQLIntrospectionSchema">The introspectionSchema to validate against</param>
 /// <param name="operationType">The operationType to validate against</param>
 /// <returns>An empty list if no errors were found or a <see cref="ValidationError"/> for each error found</returns>
 public static IEnumerable <ValidationError> ValidateGraphQLType <T>(this GraphQLIntrospectionSchema graphQLIntrospectionSchema, GraphQLOperationType operationType)
 {
     return(ValidateGraphQLType <T>(graphQLIntrospectionSchema, operationType, new GraphQLFieldBuilder()));
 }
コード例 #6
0
        private static IEnumerable <ValidationError> ValidateSelectionSet(GraphQLIntrospectionSchema graphQLIntrospectionSchema, IEnumerable <GraphQLField> selectionSet, GraphQLIntrospectionFullType graphQLIntrospectionType, GraphQLOperationType operationType, string fieldPath = null, bool rootLevel = false)
        {
            foreach (var selection in selectionSet)
            {
                // Get fieldPath
                var selectionFieldPath = fieldPath == null ? selection.Field : string.Join(".", fieldPath, selection.Field);

                // Get field from introspection
                var introspectionField = graphQLIntrospectionType.Fields.SingleOrDefault(e => e.Name == selection.Field);
                if (introspectionField == null)
                {
                    yield return(new ValidationError(selectionFieldPath, ValidationType.Field_Not_Found, selection));

                    continue;
                }

                // IsDeprecated
                if (introspectionField.IsDeprecated)
                {
                    yield return(new ValidationError(selectionFieldPath, ValidationType.Field_Deprecated, selection));
                }

                // Validate arguments
                foreach (var argument in selection.Arguments)
                {
                    // Get argument path
                    var argumentPath = $"{selectionFieldPath}({argument.ArgumentName})";

                    // Get argument
                    var introspectionArgument = introspectionField.Args.SingleOrDefault(arg => arg.Name == argument.ArgumentName);

                    if (introspectionArgument == null)
                    {
                        yield return(new ValidationError(selectionFieldPath, ValidationType.Argument_Not_Found, selection));

                        continue;
                    }

                    // Validate type
                    var typeName = GetTypeName(introspectionArgument.Type);
                    if (!string.Equals(typeName, argument.ArgumentType, StringComparison.OrdinalIgnoreCase))
                    {
                        yield return(new ValidationError(selectionFieldPath, ValidationType.Argument_Invalid_Type, selection, introspectionArgument.Type.Name, argument.ArgumentType));
                    }
                }

                // Switch on type kind (ignore __typename since union can only have __typename as selectionSet)
                var hasSelectionSet = selection.SelectionSet.Any(f => f.Field != "__typename");

                // Get concrete type
                GraphQLIntrospectionFullType graphQLType = GetSubtype(graphQLIntrospectionSchema, introspectionField.Type);

                // Get kind
                switch (graphQLType.Kind)
                {
                case GraphQLTypeKind.Scalar:
                case GraphQLTypeKind.Union:
                case GraphQLTypeKind.Enum:
                    // If Scalar/Union/Enum we cannot have selectionSet
                    if (hasSelectionSet)
                    {
                        yield return(new ValidationError(selectionFieldPath, ValidationType.Field_Cannot_Have_SelectionSet, selection));
                    }
                    break;

                case GraphQLTypeKind.Object:
                case GraphQLTypeKind.Interface:
                    // Object/Interface should have selectionSet
                    if (!hasSelectionSet)
                    {
                        yield return(new ValidationError(selectionFieldPath, ValidationType.Field_Should_Have_SelectionSet, selection));
                    }
                    break;

                default:
                    // Report error
                    throw new NotImplementedException($"{nameof(GraphQLTypeKind)} {introspectionField.Type.Kind} not implemented for fields");
                }

                // TODO: Validation should also validate type is correct for instance if GraphQLString is having the type String

                // Validate type
                if (selection.BaseType != null)
                {
                    if (graphQLType.Kind == GraphQLTypeKind.Enum || graphQLType.Kind == GraphQLTypeKind.Scalar)
                    {
                        foreach (var error in ValidateNonNullScalar(selectionFieldPath, selection, IsListType(introspectionField.Type), IsNonNull(introspectionField.Type), graphQLType))
                        {
                            yield return(error);
                        }
                    }

                    switch (graphQLType.Kind)
                    {
                    case GraphQLTypeKind.Enum:
                        foreach (var error in ValidateEnum(selectionFieldPath, selection, IsListType(introspectionField.Type), IsNonNull(introspectionField.Type), graphQLType))
                        {
                            yield return(error);
                        }
                        break;

                    case GraphQLTypeKind.Scalar:
                        foreach (var error in ValidateScalar(selectionFieldPath, selection, IsListType(introspectionField.Type), IsNonNull(introspectionField.Type), graphQLType))
                        {
                            yield return(error);
                        }
                        break;
                    }
                }

                // Validate selectionSet
                if (hasSelectionSet)
                {
                    // Validate selectionSet
                    foreach (var result in
                             ValidateSelectionSet(graphQLIntrospectionSchema, selection.SelectionSet, graphQLType, operationType, selectionFieldPath))
                    {
                        yield return(result);
                    }

                    // Validate possible types
                    foreach (var possibleType in selection.TargetTypes)
                    {
                        // Get fieldPath for possible type
                        var possibleTypeFieldPath = $"{selectionFieldPath}[{possibleType.Key}]";

                        // Get type
                        var introspectionPossibleType = GetTypeByName(graphQLIntrospectionSchema, possibleType.Key);
                        if (introspectionPossibleType == null)
                        {
                            yield return(new ValidationError(possibleTypeFieldPath, ValidationType.PossibleType_Not_Found, selection));

                            continue;
                        }

                        // Validate selectionSet
                        foreach (var result in
                                 ValidateSelectionSet(graphQLIntrospectionSchema, possibleType.Value.SelectionSet, introspectionPossibleType, operationType, possibleTypeFieldPath))
                        {
                            yield return(result);
                        }
                    }
                }
            }
        }
コード例 #7
0
 private static GraphQLIntrospectionFullType GetTypeByName(GraphQLIntrospectionSchema graphQLIntrospectionSchema, string name)
 {
     return(graphQLIntrospectionSchema.Types.SingleOrDefault(type => string.Equals(type.Name, name, StringComparison.OrdinalIgnoreCase)));
 }
コード例 #8
0
        private static GraphQLIntrospectionFullType GetIntrospectionType(GraphQLIntrospectionFullType graphQLType, GraphQLIntrospectionSchema schema)
        {
            List <GraphQLIntrospectionField> fields = new List <GraphQLIntrospectionField>();

            if (graphQLType.Fields != null)
            {
                fields.AddRange(graphQLType.Fields);
            }

            // If it's the query type
            if (graphQLType.Name == schema.QueryType.Name)
            {
                // Add schema
                fields.Add(new GraphQLIntrospectionField
                {
                    Name = Implicit_Schema_Name,
                    Type = new GraphQLIntrospectionTypeRef
                    {
                        Kind   = GraphQLTypeKind.NonNull,
                        OfType = new GraphQLIntrospectionTypeRef
                        {
                            Kind = GraphQLTypeKind.Object,
                            Name = Implicit_Schema_Type
                        }
                    }
                });

                // Add type
                fields.Add(new GraphQLIntrospectionField
                {
                    Name = Implicit_Type_Name,
                    Type = new GraphQLIntrospectionTypeRef
                    {
                        Kind = GraphQLTypeKind.Object,
                        Name = Implicit_Type_Type
                    },
                    Args = new List <GraphQLIntrospectionInputValue>
                    {
                        new GraphQLIntrospectionInputValue
                        {
                            Name = Implicit_Type_Argument_Name,
                            Type = new GraphQLIntrospectionTypeRef
                            {
                                Kind   = GraphQLTypeKind.NonNull,
                                OfType = new GraphQLIntrospectionTypeRef
                                {
                                    Kind = GraphQLTypeKind.Scalar,
                                    Name = Implicit_Type_Argument_Type
                                }
                            }
                        }
                    }
                });
            }

            // Add typename
            fields.Add(new GraphQLIntrospectionField
            {
                Name = Implicit_TypeName_Name,
                Type = new GraphQLIntrospectionTypeRef
                {
                    Kind = GraphQLTypeKind.Scalar,
                    Name = Implicit_TypeName_Type
                }
            });

            return(new GraphQLIntrospectionFullType
            {
                Description = graphQLType.Description,
                EnumValues = graphQLType.EnumValues,
                Fields = fields.AsEnumerable(),
                InputFields = graphQLType.InputFields,
                Interfaces = graphQLType.Interfaces,
                Kind = graphQLType.Kind,
                Name = graphQLType.Name,
                PossibleTypes = graphQLType.PossibleTypes
            });
        }