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; }
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); } }