public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            if (context.WebSockets.IsWebSocketRequest || !context.Request.Path.StartsWithSegments(_path))
            {
                await next(context);

                return;
            }

            // Handle requests as per recommendation at http://graphql.org/learn/serving-over-http/
            var httpRequest    = context.Request;
            var gqlRequest     = new GraphQLRequest();
            var documentWriter = new DocumentWriter(Formatting.Indented, _schema.GetJsonSerializerSettings());

            if (HttpMethods.IsGet(httpRequest.Method) || (HttpMethods.IsPost(httpRequest.Method) && httpRequest.Query.ContainsKey(GraphQLRequest.QueryKey)))
            {
                ExtractGraphQLRequestFromQueryString(httpRequest.Query, gqlRequest);
            }
            else if (HttpMethods.IsPost(httpRequest.Method))
            {
                if (!MediaTypeHeaderValue.TryParse(httpRequest.ContentType, out var mediaTypeHeader))
                {
                    await WriteBadRequestResponseAsync(context, documentWriter, $"Invalid 'Content-Type' header: value '{httpRequest.ContentType}' could not be parsed.");

                    return;
                }

                switch (mediaTypeHeader.MediaType)
                {
                case JsonContentType:
                    gqlRequest = Deserialize <GraphQLRequest>(httpRequest.Body);
                    break;

                case GraphQLContentType:
                    gqlRequest.Query = await ReadAsStringAsync(httpRequest.Body);

                    break;

                case FormUrlEncodedContentType:
                    var formCollection = await httpRequest.ReadFormAsync();

                    ExtractGraphQLRequestFromPostBody(formCollection, gqlRequest);
                    break;

                default:
                    await WriteBadRequestResponseAsync(context, documentWriter, $"Invalid 'Content-Type' header: non-supported media type. Must be of '{JsonContentType}', '{GraphQLContentType}', or '{FormUrlEncodedContentType}'. See: http://graphql.org/learn/serving-over-http/.");

                    return;
                }
            }

            var executer = new DocumentExecuter();
            var result   = await executer.ExecuteAsync(x =>
            {
                x.Schema                  = _schema;
                x.OperationName           = gqlRequest.OperationName;
                x.Query                   = gqlRequest.Query;
                x.Inputs                  = gqlRequest.GetInputs();
                x.UserContext             = _userContextBuilder.BuildContext();
                x.ValidationRules         = new[] { new AuthenticationValidationRule() }.Concat(DocumentValidator.CoreRules);
                x.CancellationToken       = context.RequestAborted;
                x.ComplexityConfiguration = _complexityConfigurationFactory.GetComplexityConfiguration();
            });

            if (result.Errors != null)
            {
                _logger.LogError("GraphQL execution error(s): {Errors}", result.Errors);
            }

            await WriteResponseAsync(context, documentWriter, result);
        }
 private static void ExtractGraphQLRequestFromQueryString(IQueryCollection qs, GraphQLRequest gqlRequest)
 {
     gqlRequest.Query         = qs.TryGetValue(GraphQLRequest.QueryKey, out var queryValues) ? queryValues[0] : null;
     gqlRequest.Variables     = qs.TryGetValue(GraphQLRequest.VariablesKey, out var variablesValues) ? JObject.Parse(variablesValues[0]) : null;
     gqlRequest.OperationName = qs.TryGetValue(GraphQLRequest.OperationNameKey, out var operationNameValues) ? operationNameValues[0] : null;
 }
 private static void ExtractGraphQLRequestFromPostBody(IFormCollection fc, GraphQLRequest gqlRequest)
 {
     gqlRequest.Query         = fc.TryGetValue(GraphQLRequest.QueryKey, out var queryValues) ? queryValues[0] : null;
     gqlRequest.Variables     = fc.TryGetValue(GraphQLRequest.VariablesKey, out var variablesValue) ? JObject.Parse(variablesValue[0]) : null;
     gqlRequest.OperationName = fc.TryGetValue(GraphQLRequest.OperationNameKey, out var operationNameValues) ? operationNameValues[0] : null;
 }
Example #4
0
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            if (context.WebSockets.IsWebSocketRequest)
            {
                await next(context);

                return;
            }

            // Handle requests as per recommendation at http://graphql.org/learn/serving-over-http/
            var httpRequest    = context.Request;
            var gqlRequest     = new GraphQLRequest();
            var documentWriter = new DocumentWriter(_schema.GetJsonSerializerSettings());

            if (HttpMethods.IsGet(httpRequest.Method) || (HttpMethods.IsPost(httpRequest.Method) && httpRequest.Query.ContainsKey(GraphQLRequest.QueryKey)))
            {
                ExtractGraphQLRequestFromQueryString(httpRequest.Query, gqlRequest);
            }
            else if (HttpMethods.IsPost(httpRequest.Method))
            {
                if (!MediaTypeHeaderValue.TryParse(httpRequest.ContentType, out var mediaTypeHeader))
                {
                    await WriteBadRequestResponseAsync(context, documentWriter, $"Invalid 'Content-Type' header: value '{httpRequest.ContentType}' could not be parsed.");

                    return;
                }

                switch (mediaTypeHeader.MediaType)
                {
                case JsonContentType:
                    gqlRequest = Deserialize <GraphQLRequest>(httpRequest.Body);
                    break;

                case GraphQLContentType:
                    gqlRequest.Query = await ReadAsStringAsync(httpRequest.Body);

                    break;

                case FormUrlEncodedContentType:
                    var formCollection = await httpRequest.ReadFormAsync();

                    ExtractGraphQLRequestFromPostBody(formCollection, gqlRequest);
                    break;

                default:
                    await WriteBadRequestResponseAsync(context, documentWriter, $"Invalid 'Content-Type' header: non-supported media type. Must be of '{JsonContentType}', '{GraphQLContentType}', or '{FormUrlEncodedContentType}'. See: http://graphql.org/learn/serving-over-http/.");

                    return;
                }
            }

            IEnumerable <IValidationRule> validationRules;

            try
            {
                validationRules = _container.GetAllInstances <IValidationRule>();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, ex);
                validationRules = new IValidationRule[0];
            }

            var executer = new DocumentExecuter();
            var result   = await executer.ExecuteAsync(x =>
            {
                x.Schema                  = _schema;
                x.OperationName           = gqlRequest.OperationName;
                x.Query                   = gqlRequest.Query;
                x.Inputs                  = gqlRequest.GetInputs();
                x.UserContext             = _userContextBuilder.BuildContext();
                x.ValidationRules         = validationRules.Concat(DocumentValidator.CoreRules);
                x.CancellationToken       = context.RequestAborted;
                x.ComplexityConfiguration = _complexityConfigurationFactory.GetComplexityConfiguration();
            });

            if (result.Errors?.Any(x => x.Code == "auth-required") == true && context.Response.Headers.ContainsKey("Token-Expired"))
            {
                await WriteUnauthorizedResponseAsync(context, documentWriter, result);
            }
            else
            {
                await WriteResponseAsync(context, documentWriter, result);
            }
        }