public static IQueryResult StateInvalidForOperationVariableCoercion() => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage( "There is no operation on the context which can be used to coerce " + "variables.") .Build());
public static IQueryResult StateInvalidForOperationExecution() => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage( "Either now compiled operation was found or the variables " + "have not been coerced.") .Build());
public static IQueryResult RootTypeNotFound(OperationType operationType) => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage( "The specified root type `{0}` is not supported by this server.", operationType) .Build());
public static IQueryResult StateInvalidForOperationResolver() => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage( "Either no query document exists or the document " + "validation result is invalid.") .Build());
public async Task InvokeAsync(IQueryContext context) { try { IHttpClientFactory httpClientFactory = context.Services.GetRequiredService <IHttpClientFactory>(); context.Result = await _client.FetchAsync( context.Request, httpClientFactory.CreateClient(_schemaName), context.Services.GetServices <IHttpQueryRequestInterceptor>(), context.RequestAborted) .ConfigureAwait(false); } catch (HttpRequestException ex) { IError error = _errorHandler.CreateUnexpectedError(ex) .SetCode(ErrorCodes.HttpRequestException) .Build(); context.Exception = ex; context.Result = QueryResultBuilder.CreateError(error); } await _next.Invoke(context).ConfigureAwait(false); }
public async ValueTask InvokeAsync(IRequestContext context) { if (context.Document is null) { context.Result = StateInvalidForDocumentValidation(); } else { if (context.ValidationResult is null) { using (_diagnosticEvents.ValidateDocument(context)) { context.ValidationResult = _documentValidator.Validate( context.Schema, context.Document, context.ContextData); } } if (context.ValidationResult is { HasErrors : true } validationResult) { context.Result = QueryResultBuilder.CreateError( validationResult.Errors, new Dictionary <string, object?> { { WellKnownContextData.ValidationErrors, true } }); _diagnosticEvents.ValidationErrors(context, validationResult.Errors); }
public async ValueTask InvokeAsync(IRequestContext context) { if (context.Document is null) { // TODO : ErrorHelper context.Result = QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage("Cannot Validate") .Build()); } else { if (context.ValidationResult is null) { using (_diagnosticEvents.ValidateDocument(context)) { context.ValidationResult = _documentValidator.Validate(context.Schema, context.Document !); } } if (context.ValidationResult is { HasErrors : true } validationResult) { context.Result = QueryResultBuilder.CreateError(validationResult.Errors); _diagnosticEvents.ValidationErrors(context, validationResult.Errors); }
public static Task SerializeAsync( this IQueryResultSerializer serializer, IExecutionResult result, Stream outputStream, CancellationToken cancellationToken) { if (result is IReadOnlyQueryResult queryResult) { using (queryResult) { return(serializer.SerializeAsync( queryResult, outputStream, cancellationToken)); } } else { // TODO : resources return(serializer.SerializeAsync( QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage("Result type not supported.") .SetCode(ErrorCodes.Serialization.ResultTypeNotSupported) .Build()), outputStream, cancellationToken)); } }
private async Task <IReadOnlyQueryResult> FetchAsync( IReadOnlyQueryRequest request, HttpContent requestContent, HttpClient httpClient, IEnumerable <IHttpQueryRequestInterceptor>?interceptors, CancellationToken cancellationToken) { HttpResponseMessage message = await FetchInternalAsync(requestContent, httpClient).ConfigureAwait(false); using (Stream stream = await message.Content.ReadAsStreamAsync().ConfigureAwait(false)) { object response = await BufferHelper.ReadAsync( stream, (buffer, bytesBuffered) => ParseJson(buffer, bytesBuffered), cancellationToken) .ConfigureAwait(false); IReadOnlyQueryResult queryResult = response is IReadOnlyDictionary <string, object> d ? HttpResponseDeserializer.Deserialize(d) : QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage("Could not deserialize query response.") .Build()); if (interceptors is { })
public static IQueryResult UnknownSubscriptionError(Exception ex) => QueryResultBuilder.CreateError( ErrorBuilder .New() .SetException(ex) .SetCode(ErrorCodes.Execution.TaskProcessingError) .SetMessage(AspNetCoreResources.Subscription_SendResultsAsync) .Build());
public static IQueryResult OperationKindNotAllowed() => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage("The specified operation kind is not allowed.") .Build(), new Dictionary <string, object?> { { WellKnownContextData.OperationNotAllowed, null } });
public static IQueryResult InvalidTypeName(string typeName) => QueryResultBuilder.CreateError( new Error( "The type name is invalid.", code: ErrorCodes.Server.InvalidTypeName, extensions: new Dictionary <string, object?> { { "typeName", typeName } }));
public static IQueryResult TypeNotFound(string typeName) => QueryResultBuilder.CreateError( new Error( $"The type `{typeName}` does not exist.", code: ErrorCodes.Server.TypeDoesNotExist, extensions: new Dictionary <string, object?> { { "typeName", typeName } }));
private async Task HandleRequestAsync(HttpContext context) { // 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. GraphQLRequest request; using (_diagnosticEvents.ParseHttpRequest(context)) { try { request = _requestParser.ReadParamsRequest(context.Request.Query); } 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 { GraphQLServerOptions?options = context.GetGraphQLServerOptions(); result = await ExecuteSingleAsync( context, requestExecutor, requestInterceptor, _diagnosticEvents, request, options is null or { AllowedGetOperations : AllowedGetOperations.Query } ?_onlyQueries : null); }
private async Task <IQueryResult> ExecuteNextAsync( IReadOnlyQueryRequest request, CancellationToken cancellationToken) { try { DocumentNode document = request.Query is QueryDocument d ? d.Document : Utf8GraphQLParser.Parse(request.Query !.AsSpan()); OperationDefinitionNode operation = document.GetOperation(request.OperationName); if (document != _previous) { _fragments = document.GetFragments(); _visitationMap.Initialize(_fragments); } operation.Accept( _visitor, _visitationMap, n => VisitorAction.Continue); _previous = document; document = RewriteDocument(operation); operation = (OperationDefinitionNode)document.Definitions[0]; IReadOnlyDictionary <string, object?>?variableValues = MergeVariables(request.VariableValues, operation); request = QueryRequestBuilder.From(request) .SetQuery(document) .SetVariableValues(variableValues) .AddExportedVariables(_exportedVariables) .SetQueryName(null) // TODO ... should we create a name here? .SetQueryHash(null) .Create(); return((IReadOnlyQueryResult)await _requestExecutor.ExecuteAsync( request, cancellationToken) .ConfigureAwait(false)); } catch (GraphQLException ex) { return(QueryResultBuilder.CreateError(ex.Errors)); } catch (Exception ex) { return(QueryResultBuilder.CreateError( _errorHandler.Handle( _errorHandler.CreateUnexpectedError(ex).Build()))); } }
public static IQueryResult MaxComplexityReached( int complexity, int allowedComplexity) => QueryResultBuilder.CreateError( new Error( ErrorHelper_MaxComplexityReached, ErrorCodes.Execution.ComplexityExceeded, extensions: new Dictionary <string, object?> { { nameof(complexity), complexity }, { nameof(allowedComplexity), allowedComplexity } }));
private async Task SendResultsAsync() { try { await foreach (IQueryResult result in _responseStream.ReadResultsAsync().WithCancellation(_cts.Token)) { using (result) { await _connection.SendAsync(new DataResultMessage(Id, result), _cts.Token); } } if (!_cts.IsCancellationRequested) { await _connection.SendAsync(new DataCompleteMessage(Id), _cts.Token); Completed?.Invoke(this, EventArgs.Empty); } } catch (OperationCanceledException) { } catch (ObjectDisposedException) { } catch (Exception ex) { if (!_cts.IsCancellationRequested) { IError error = ErrorBuilder .New() .SetException(ex) .SetCode(ErrorCodes.Execution.TaskProcessingError) .SetMessage("Unexpected Execution Error") .Build(); IQueryResult result = QueryResultBuilder.CreateError(error); try { await _connection.SendAsync(new DataResultMessage(Id, result), _cts.Token); } finally { await _connection.SendAsync(new DataCompleteMessage(Id), _cts.Token); Completed?.Invoke(this, EventArgs.Empty); } } } finally { Dispose(); } }
/// <summary> /// Execute the current HttpContext provided using HotChocolate GraphQL and the currently configured pipeline. /// ALL parsing, and processing of the Query of the request will be handled by existing HotChoclate HttpPost & HttpGet /// middleware, this class will only proxy the context into HC for execution, and handle unexpected errors. /// NOTE: An EmptyResult() response is returned because that is what must be returned by the AzureFunction; because HotChocolate /// has already processed the request and started the response (e.g. StatusCode will be set by HC) an EmptyResult() response /// will prevent the Azure Functions framework from attempting to set it again resulting in a a Host error/crash. /// </summary> /// <param name="httpContext"></param> /// <param name="logger"></param> /// <param name="cancellationToken"></param> /// <returns> /// Returns an EmptyResult() response because HotChocolate has already processed the request and started the response /// (e.g. StatusCode will be set by HC) and an EmptyResult() response will prevent the Azure Functions framework from /// attempting to set it again resulting in a a Host error/crash. /// </returns> public async Task <IActionResult> ExecuteFunctionsQueryAsync(HttpContext httpContext, ILogger logger, CancellationToken cancellationToken) { try { //Use the Middleware Proxy to Invoke the pre-configured pipeline for Http POST & GET processing... var httpMiddlewareProxy = this.AzureFunctionsMiddlewareProxy; await httpMiddlewareProxy.InvokeAsync(httpContext).ConfigureAwait(false); } //NOTE: We Implement error handling that matches the Existing HttpPostMiddleware, to ensure that all code // has top level error handling for Graph processing. catch (GraphQLRequestException ex) { //If Debugging is enabled then Log the Errors to AzureFunctions framework (e.g. Application Insights) logger.LogDebug(ex, $"{nameof(GraphQLRequestException)} occurred while processing the GraphQL request; {ex.Message}."); // 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. IErrorHandler errorHandler = await this.AzureFunctionsMiddlewareProxy.GetErrorHandlerAsync(cancellationToken).ConfigureAwait(false); IQueryResult errorResult = QueryResultBuilder.CreateError(errorHandler.Handle(ex.Errors)); await HandleGraphQLErrorResponseAsync(httpContext, HttpStatusCode.BadRequest, errorResult); } catch (Exception exc) { //Log all Unknown Exceptions as GraphQLExceptions to Azure Framework (e.g. Application Insights). logger.LogError(exc, "An unhandled exception occurred while processing the GraphQL request."); // An unknown and unexpected GraphQL request exception was encountered. // In this case we will return HTTP status code 500 and return a GraphQL error result. IErrorHandler errorHandler = await this.AzureFunctionsMiddlewareProxy.GetErrorHandlerAsync(cancellationToken).ConfigureAwait(false); IError error = errorHandler.CreateUnexpectedError(exc).Build(); IQueryResult errorResult = QueryResultBuilder.CreateError(error); HttpStatusCode statusCode = exc is HttpRequestException ? HttpStatusCode.BadRequest : HttpStatusCode.InternalServerError; await HandleGraphQLErrorResponseAsync(httpContext, statusCode, errorResult).ConfigureAwait(false); } //Safely resolve the .Net Core request with Empty Result because the Response has already been handled! //NOTE: We Must return EmptyResult() so that No Action is taken on the Response or else an error will occur // since HotChocolate has ALREADY started (e.g. processed) the response, and the Status Code is already set! //For More Info See: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.emptyresult?view=aspnetcore-5.0 return(new EmptyResult()); }
/// <summary> /// /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task InvokeAsync(HttpContext context) { if (_isPathValid(context) && CanHandleRequest(context)) { try { await HandleRequestAsync(context) .ConfigureAwait(false); } catch (ArgumentException) { context.Response.StatusCode = _badRequest; } catch (NotSupportedException) { context.Response.StatusCode = _badRequest; } catch (SyntaxException ex) { IError error = ErrorBuilder.New() .SetMessage(ex.Message) .AddLocation(ex.Line, ex.Column) .SetCode(ErrorCodes.Execution.SyntaxError) .Build(); ErrorHandler.Handle(error); var errorResult = QueryResultBuilder.CreateError(error); SetResponseHeaders(context.Response, _serializer.ContentType); await _serializer.SerializeAsync(errorResult, context.Response.Body) .ConfigureAwait(false); } catch (QueryException ex) { var errorResult = QueryResultBuilder.CreateError( ErrorHandler.Handle(ex.Errors)); SetResponseHeaders(context.Response, _serializer.ContentType); await _serializer.SerializeAsync(errorResult, context.Response.Body) .ConfigureAwait(false); } } else if (Next != null) { await Next.Invoke(context).ConfigureAwait(false); } }
public async ValueTask InvokeAsync(IRequestContext context) { try { await _next(context).ConfigureAwait(false); } catch (GraphQLException ex) { context.Exception = ex; context.Result = QueryResultBuilder.CreateError(_errorHandler.Handle(ex.Errors)); } catch (Exception ex) { context.Exception = ex; IError error = _errorHandler.CreateUnexpectedError(ex).Build(); context.Result = QueryResultBuilder.CreateError(_errorHandler.Handle(error)); } }
public async ValueTask InvokeAsync(IRequestContext context) { if (context.Document is null && context.Request.Query is not null) { var success = true; try { using (_diagnosticEvents.ParseDocument(context)) { context.DocumentId = ComputeDocumentHash( context.DocumentHash, context.Request.QueryHash, context.Request.Query); context.Document = ParseDocument(context.Request.Query); } } catch (SyntaxException ex) { success = false; IError error = context.ErrorHandler.Handle( ErrorBuilder.New() .SetMessage(ex.Message) .SetCode(ErrorCodes.Execution.SyntaxError) .AddLocation(ex.Line, ex.Column) .Build()); context.Exception = ex; context.Result = QueryResultBuilder.CreateError(error); _diagnosticEvents.SyntaxError(context, error); } if (success) { await _next(context).ConfigureAwait(false); } }
private async Task HandleRequestAsync(HttpContext context) { // 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. GraphQLRequest request = _requestParser.ReadParamsRequest(context.Request.Query); result = await ExecuteSingleAsync( context, requestExecutor, requestInterceptor, request); } 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 ValueTask InvokeAsync(IRequestContext context) { if (context.Document is null) { context.Result = StateInvalidForDocumentValidation(); } else { using (_diagnosticEvents.ValidateDocument(context)) { context.ValidationResult = _documentValidator.Validate( context.Schema, context.Document, context.ContextData, context.ValidationResult is not null); } if (context.IsValidDocument) { await _next(context).ConfigureAwait(false); } else { DocumentValidatorResult validationResult = context.ValidationResult; context.Result = QueryResultBuilder.CreateError( validationResult.Errors, new Dictionary <string, object?> { { WellKnownContextData.ValidationErrors, true } }); _diagnosticEvents.ValidationErrors(context, validationResult.Errors); } } }
public static IQueryResult StateInvalidForDocumentValidation() => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage("The query request contains no document.") .SetCode(ErrorCodes.Execution.QueryNotFound) .Build());
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); }
protected override async Task HandleAsync( ISocketConnection connection, DataStartMessage message, CancellationToken cancellationToken) { var session = new CancellationTokenSource(); var combined = CancellationTokenSource.CreateLinkedTokenSource( session.Token, cancellationToken); var sessionIsHandled = false; IExecutionResult result = await ExecuteAsync(combined.Token); try { switch (result) { case SubscriptionResult subscriptionResult: // first we add the cts to the result so that they are disposed when the // subscription is disposed. subscriptionResult.RegisterDisposable(combined); // while a subscription result must be disposed we are not handling it here // and leave this responsibility to the subscription session. ISubscription subscription = GetSubscription(result); var subscriptionSession = new SubscriptionSession( session, _socketSessionInterceptor, connection, subscriptionResult, subscription, _diagnosticEvents, message.Id); connection.Subscriptions.Register(subscriptionSession); sessionIsHandled = true; break; case IResponseStream streamResult: // stream results represent deferred execution streams that use execution // resources. We need to ensure that these are disposed when we are // finished. await using (streamResult) { await HandleStreamResultAsync( connection, message, streamResult, cancellationToken); } break; case IQueryResult queryResult: // query results use pooled memory an need to be disposed after we have // used them. using (queryResult) { await HandleQueryResultAsync( connection, message, queryResult, cancellationToken); } break; default: throw DataStartMessageHandler_RequestTypeNotSupported(); } } finally { if (!sessionIsHandled) { session.Dispose(); combined.Dispose(); } } async ValueTask <IExecutionResult> ExecuteAsync(CancellationToken cancellationToken) { try { IQueryRequestBuilder requestBuilder = QueryRequestBuilder.From(message.Payload) .SetServices(connection.RequestServices); await _socketSessionInterceptor.OnRequestAsync( connection, requestBuilder, cancellationToken); return(await _requestExecutor.ExecuteAsync( requestBuilder.Create(), cancellationToken)); } catch (Exception ex) { IErrorBuilder error = _errorHandler.CreateUnexpectedError(ex); return(QueryResultBuilder.CreateError(error.Build())); } } }
public static IQueryResult ResponseTypeNotSupported() => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage("The response type is not supported.") .Build());
public static IQueryResult ParserExpectedQuery() => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage("The parse query middleware expects a valid query request.") .SetCode(ErrorCodes.Execution.Incomplete) .Build());
public static IQueryResult TypeNameIsEmpty() => QueryResultBuilder.CreateError( new Error( "The specified types argument is empty.", code: ErrorCodes.Server.TypeParameterIsEmpty));
public static IQueryResult ResponseTypeNotSupported() => QueryResultBuilder.CreateError( ErrorBuilder.New() .SetMessage(AspNetCoreResources.ErrorHelper_ResponseTypeNotSupported) .Build());