public async Task InvokeAsync(HttpContext context) { AllowedContentType contentType = ParseContentType(context.Request.ContentType); if (contentType == AllowedContentType.None) { // the content type is unknown so we will invoke the next middleware. await _next(context).ConfigureAwait(false); } else { await HandleRequestAsync(context, contentType, context.RequestAborted) .ConfigureAwait(false); } }
public async Task InvokeAsync(HttpContext context) { if (!HttpMethods.IsPost(context.Request.Method)) { // if the request is not a post request we will just invoke the next // middleware and do nothing: await NextAsync(context); } else { AllowedContentType contentType = ParseContentType(context.Request.ContentType); if (contentType == AllowedContentType.None) { // the content type is unknown so we will invoke the next middleware. await NextAsync(context); } else { await HandleRequestAsync(context, contentType); } } }
private async Task HandleRequestAsync( HttpContext context, AllowedContentType contentType) { // first we need to get the request executor to be able to execute requests. IRequestExecutor requestExecutor = await GetExecutorAsync(context.RequestAborted); IHttpRequestInterceptor requestInterceptor = requestExecutor.GetRequestInterceptor(); IErrorHandler errorHandler = requestExecutor.GetErrorHandler(); HttpStatusCode? statusCode = null; IExecutionResult?result; try { // next we parse the GraphQL request. IReadOnlyList <GraphQLRequest> requests = await _requestParser.ReadJsonRequestAsync( context.Request.Body, context.RequestAborted); switch (requests.Count) { // if the HTTP request body contains no GraphQL request structure the // whole request is invalid and we will create a GraphQL error response. case 0: { statusCode = HttpStatusCode.BadRequest; IError error = errorHandler.Handle(ErrorHelper.RequestHasNoElements()); result = QueryResultBuilder.CreateError(error); break; } // if the HTTP request body contains a single GraphQL request and we do have // the batch operations query parameter specified we need to execute an // operation batch. // // An operation batch consists of a single GraphQL request document that // contains multiple operations. The batch operation query parameter // defines the order in which the operations shall be executed. case 1 when context.Request.Query.ContainsKey(_batchOperations): { string operationNames = context.Request.Query[_batchOperations]; if (TryParseOperations(operationNames, out IReadOnlyList <string>?ops)) { result = await ExecuteOperationBatchAsync( context, requestExecutor, requestInterceptor, requests[0], ops); } else { IError error = errorHandler.Handle(ErrorHelper.InvalidRequest()); statusCode = HttpStatusCode.BadRequest; result = QueryResultBuilder.CreateError(error); } break; } // if the HTTP request body contains a single GraphQL request and // no batch query parameter is specified we need to execute a single // GraphQL request. // // Most GraphQL requests will be of this type where we want to execute // a single GraphQL query or mutation. case 1: { result = await ExecuteSingleAsync( context, requestExecutor, requestInterceptor, requests[0]); break; } // if the HTTP request body contains more than one GraphQL request than // we need to execute a request batch where we need to execute multiple // fully specified GraphQL requests at once. default: result = await ExecuteBatchAsync( context, requestExecutor, requestInterceptor, requests); break; } } catch (GraphQLRequestException ex) { // A GraphQL request exception is thrown if the HTTP request body couldn't be // parsed. In this case we will return HTTP status code 400 and return a // GraphQL error result. statusCode = HttpStatusCode.BadRequest; result = QueryResultBuilder.CreateError(errorHandler.Handle(ex.Errors)); } catch (Exception ex) { statusCode = HttpStatusCode.InternalServerError; IError error = errorHandler.CreateUnexpectedError(ex).Build(); result = QueryResultBuilder.CreateError(error); } // in any case we will have a valid GraphQL result at this point that can be written // to the HTTP response stream. Debug.Assert(result is not null, "No GraphQL result was created."); await WriteResultAsync(context.Response, result, statusCode, context.RequestAborted); }
public async Task HandleRequestAsync( HttpContext context, AllowedContentType contentType, CancellationToken cancellationToken) { // first we need to gather an executor to start execution the request. IRequestExecutor executor = await GetExecutorAsync(context.RequestAborted) .ConfigureAwait(false); IErrorHandler errorHandler = executor.Services.GetRequiredService <IErrorHandler>(); IExecutionResult?result = null; int?statusCode = null; try { IReadOnlyList <GraphQLRequest>?requests = await ReadRequestAsync( contentType, context.Request.Body, context.RequestAborted) .ConfigureAwait(false); if (requests.Count == 0) { // IError error = ErrorHandler.Handle(ErrorHelper.RequestHasNoElements()); // httpHelper.Result = CreateError(error); } else if (requests.Count == 1) { string operations = context.Request.Query[_batchOperations]; if (operations is null) { result = await ExecuteQueryAsync(context, executor, requests[0]) .ConfigureAwait(false); } else if (TryParseOperations(operations, out IReadOnlyList <string>?operationNames)) { // await ExecuteOperationBatchAsync( // httpHelper, batch[0], operationNames) // .ConfigureAwait(false); } else { // IError error = ErrorHandler.Handle(ErrorHelper.InvalidRequest()); // httpHelper.StatusCode = BadRequest; // httpHelper.Result = CreateError(error); } } else { } } catch (GraphQLRequestException ex) { statusCode = 400; IEnumerable <IError> errors = errorHandler.Handle(ex.Errors); result = QueryResultBuilder.CreateError(errors); } catch (Exception ex) { statusCode = 500; IError error = errorHandler.CreateUnexpectedError(ex).Build(); result = QueryResultBuilder.CreateError(error); } Debug.Assert(result is { });
protected async Task HandleRequestAsync( HttpContext context, AllowedContentType contentType) { // first we need to get the request executor to be able to execute requests. IRequestExecutor requestExecutor = await GetExecutorAsync(context.RequestAborted); IHttpRequestInterceptor requestInterceptor = requestExecutor.GetRequestInterceptor(); IErrorHandler errorHandler = requestExecutor.GetErrorHandler(); context.Items[WellKnownContextData.RequestExecutor] = requestExecutor; HttpStatusCode? statusCode = null; IExecutionResult?result; // next we parse the GraphQL request. IReadOnlyList <GraphQLRequest> requests; using (DiagnosticEvents.ParseHttpRequest(context)) { try { requests = await GetRequestsFromBody(context.Request, context.RequestAborted); } catch (GraphQLRequestException ex) { // A GraphQL request exception is thrown if the HTTP request body couldn't be // parsed. In this case we will return HTTP status code 400 and return a // GraphQL error result. statusCode = HttpStatusCode.BadRequest; IReadOnlyList <IError> errors = errorHandler.Handle(ex.Errors); result = QueryResultBuilder.CreateError(errors); DiagnosticEvents.ParserErrors(context, errors); goto HANDLE_RESULT; } catch (Exception ex) { statusCode = HttpStatusCode.InternalServerError; IError error = errorHandler.CreateUnexpectedError(ex).Build(); result = QueryResultBuilder.CreateError(error); DiagnosticEvents.HttpRequestError(context, error); goto HANDLE_RESULT; } } // after successfully parsing the request we now will attempt to execute the request. try { switch (requests.Count) { // if the HTTP request body contains no GraphQL request structure the // whole request is invalid and we will create a GraphQL error response. case 0: { statusCode = HttpStatusCode.BadRequest; IError error = errorHandler.Handle(ErrorHelper.RequestHasNoElements()); result = QueryResultBuilder.CreateError(error); DiagnosticEvents.HttpRequestError(context, error); break; } // if the HTTP request body contains a single GraphQL request and we do have // the batch operations query parameter specified we need to execute an // operation batch. // // An operation batch consists of a single GraphQL request document that // contains multiple operations. The batch operation query parameter // defines the order in which the operations shall be executed. case 1 when context.Request.Query.ContainsKey(_batchOperations): { string operationNames = context.Request.Query[_batchOperations]; if (TryParseOperations(operationNames, out IReadOnlyList <string>?ops)) { result = await ExecuteOperationBatchAsync( context, requestExecutor, requestInterceptor, DiagnosticEvents, requests[0], ops); } else { IError error = errorHandler.Handle(ErrorHelper.InvalidRequest()); statusCode = HttpStatusCode.BadRequest; result = QueryResultBuilder.CreateError(error); DiagnosticEvents.HttpRequestError(context, error); } break; } // if the HTTP request body contains a single GraphQL request and // no batch query parameter is specified we need to execute a single // GraphQL request. // // Most GraphQL requests will be of this type where we want to execute // a single GraphQL query or mutation. case 1: { result = await ExecuteSingleAsync( context, requestExecutor, requestInterceptor, DiagnosticEvents, requests[0]); break; } // if the HTTP request body contains more than one GraphQL request than // we need to execute a request batch where we need to execute multiple // fully specified GraphQL requests at once. default: result = await ExecuteBatchAsync( context, requestExecutor, requestInterceptor, DiagnosticEvents, requests); break; } } catch (GraphQLException ex) { // This allows extensions to throw GraphQL exceptions in the GraphQL interceptor. statusCode = null; // we let the serializer determine the status code. result = QueryResultBuilder.CreateError(ex.Errors); foreach (IError error in ex.Errors) { DiagnosticEvents.HttpRequestError(context, error); } } catch (Exception ex) { statusCode = HttpStatusCode.InternalServerError; IError error = errorHandler.CreateUnexpectedError(ex).Build(); result = QueryResultBuilder.CreateError(error); DiagnosticEvents.HttpRequestError(context, error); } HANDLE_RESULT: IDisposable? formatScope = null; try { // if cancellation is requested we will not try to attempt to write the result to the // response stream. if (context.RequestAborted.IsCancellationRequested) { return; } // in any case we will have a valid GraphQL result at this point that can be written // to the HTTP response stream. Debug.Assert(result is not null, "No GraphQL result was created."); if (result is IQueryResult queryResult) { formatScope = DiagnosticEvents.FormatHttpResponse(context, queryResult); } await WriteResultAsync(context.Response, result, statusCode, context.RequestAborted); } finally { // we must dispose the diagnostic scope first. formatScope?.Dispose(); // query results use pooled memory an need to be disposed after we have // used them. if (result is IAsyncDisposable asyncDisposable) { await asyncDisposable.DisposeAsync(); } if (result is IDisposable disposable) { disposable.Dispose(); } } }