public async ValueTask InvokeAsync(IRequestContext context) { IQueryRequest request = context.Request; var addToCache = true; if (context.Document is null) { if (request.QueryId != null && _documentCache.TryGetDocument(request.QueryId, out DocumentNode document)) { context.DocumentId = request.QueryId; context.Document = document; context.ValidationResult = DocumentValidatorResult.Ok; context.IsCachedDocument = true; addToCache = false; _diagnosticEvents.RetrievedDocumentFromCache(context); } else if (request.QueryHash != null && _documentCache.TryGetDocument(request.QueryHash, out document)) { context.DocumentId = request.QueryHash; context.Document = document; context.ValidationResult = DocumentValidatorResult.Ok; context.IsCachedDocument = true; addToCache = false; _diagnosticEvents.RetrievedDocumentFromCache(context); } else if (request.QueryHash is null && request.Query != null) { context.DocumentHash = _documentHashProvider.ComputeHash(request.Query.AsSpan()); if (_documentCache.TryGetDocument(context.DocumentHash, out document)) { context.DocumentId = context.DocumentHash; context.Document = document; context.ValidationResult = DocumentValidatorResult.Ok; context.IsCachedDocument = true; addToCache = false; _diagnosticEvents.RetrievedDocumentFromCache(context); } } } await _next(context).ConfigureAwait(false); if (addToCache && context.DocumentId != null && context.Document != null && context.IsValidDocument) { _documentCache.TryAddDocument(context.DocumentId, context.Document); _diagnosticEvents.AddedDocumentToCache(context); } }
private async Task <IQueryDescriptor> LoadAsync( string name, string fileName, DocumentNode document) { OperationDefinitionNode operation = document.Definitions.OfType <OperationDefinitionNode>() .FirstOrDefault(t => t.Name is null); if (operation != null) { throw new GeneratorException(HCErrorBuilder.New() .SetMessage("All operations have to have a name in order " + "to work with Strawberry Shake. Check the specified " + "operation and give it a name, then retry generating " + "the client.") .SetCode("OPERATION_NO_NAME") .AddLocation(operation) .SetExtension("fileName", fileName) .Build()); } DocumentNode rewritten = AddTypeNameQueryRewriter.Rewrite(document); byte[] rewrittenBuffer; var serializer = new QuerySyntaxSerializer(false); using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream)) { using (var writer = new DocumentWriter(sw)) { serializer.Visit(rewritten, writer); } } await stream.FlushAsync().ConfigureAwait(false); rewrittenBuffer = stream.ToArray(); } string hash = _hashProvider.ComputeHash(rewrittenBuffer); var descriptor = new QueryDescriptor( name, _namespace, _hashProvider.Name, hash, rewrittenBuffer, document); _descriptors.Add(descriptor); return(descriptor); }
private IReadOnlyList <GraphQLRequest> ParseQuery( byte[] buffer, int bytesBuffered) { var graphQLData = new ReadOnlySpan <byte>(buffer); graphQLData = graphQLData.Slice(0, bytesBuffered); var requestParser = new Utf8GraphQLParser(graphQLData, _parserOptions); string queryHash = _documentHashProvider.ComputeHash(graphQLData); DocumentNode document = requestParser.Parse(); return(new[] { new GraphQLRequest(document, queryHash) }); }
private string ResolveQueryKey(IReadOnlyQueryRequest request) { string queryKey = request.QueryName; if (queryKey is null || request.Query != null) { queryKey = request.QueryHash is null ? _documentHashProvider.ComputeHash( request.Query.ToSpan()) : request.QueryHash; } return(queryKey); }
private GraphQLRequest ParseRequest() { var request = new Request(); _reader.Expect(TokenKind.LeftBrace); while (_reader.Kind != TokenKind.RightBrace) { ParseRequestProperty(ref request); } if (request.IsQueryNull && request.NamedQuery == null) { // TODO : resources throw new SyntaxException( _reader, "Either the query `property` or the `namedQuery` " + "property have to have a value."); } DocumentNode document; if (_useCache) { if (request.NamedQuery is null) { request.NamedQuery = _hashProvider.ComputeHash(request.Query); } if (!_cache.TryGetDocument(request.NamedQuery, out document)) { document = ParseQuery(in request); } } else { document = ParseQuery(in request); } return(new GraphQLRequest ( document, request.NamedQuery, request.OperationName, request.Variables, request.Extensions )); }
public async Task ActivePersistedQueries_Invalid_Hash() { // arrange var serviceCollection = new ServiceCollection(); // configure presistence serviceCollection.AddGraphQLSchema(b => b .AddDocumentFromString("type Query { foo: String }") .AddResolver("Query", "foo", "bar")); serviceCollection.AddQueryExecutor(b => b .AddSha256DocumentHashProvider(HashFormat.Hex) .UseActivePersistedQueryPipeline()); // add in-memory query storage serviceCollection.AddSingleton <InMemoryQueryStorage>(); serviceCollection.AddSingleton <IReadStoredQueries>(sp => sp.GetRequiredService <InMemoryQueryStorage>()); serviceCollection.AddSingleton <IWriteStoredQueries>(sp => sp.GetRequiredService <InMemoryQueryStorage>()); IServiceProvider services = serviceCollection.BuildServiceProvider(); IQueryExecutor executor = services.GetRequiredService <IQueryExecutor>(); IDocumentHashProvider hashProvider = services.GetRequiredService <IDocumentHashProvider>(); InMemoryQueryStorage storage = services.GetRequiredService <InMemoryQueryStorage>(); var query = new QuerySourceText("{ foo }"); var hash = hashProvider.ComputeHash(query.AsSpan()); // act IExecutionResult result = await executor.ExecuteAsync( QueryRequestBuilder.New() .SetQuery(query.Text) .SetQueryName(hash) .AddExtension("persistedQuery", new Dictionary <string, object> { { "sha256Hash", "123" } }) .Create()); // assert Assert.False(storage.WrittenQuery.HasValue); result.ToJson().MatchSnapshot(); }
public async Task InvokeAsync(IQueryContext context) { if (IsContextIncomplete(context)) { context.Result = QueryResult.CreateError( ErrorBuilder.New() .SetMessage(CoreResources .ParseQueryMiddleware_InComplete) .Build()); } else { Activity activity = _diagnosticEvents.BeginParsing(context); try { bool documentRetrievedFromCache = true; string queryKey = context.Request.QueryHash ?? context.Request.QueryName; if (queryKey is null) { queryKey = _documentHashProvider.ComputeHash( context.Request.Query.ToSource()); } context.QueryKey = queryKey; context.CachedQuery = _queryCache.GetOrCreate( queryKey, () => { documentRetrievedFromCache = false; DocumentNode document = ParseDocument(context.Request.Query); return(new CachedQuery(queryKey, document)); }); context.Document = context.CachedQuery.Document; context.ContextData[ContextDataKeys.DocumentCached] = documentRetrievedFromCache; } finally { _diagnosticEvents.EndParsing(activity, context); } } await _next(context).ConfigureAwait(false); }
private static DocumentModel CreateDocumentModel( IDocumentAnalyzerContext context, string name, DocumentNode original, IDocumentHashProvider hashProvider) { DocumentNode optimized = TypeNameQueryRewriter.Rewrite(original); string serialized = QuerySyntaxSerializer.Serialize(optimized, false); byte[] buffer = Encoding.UTF8.GetBytes(serialized); string hash = hashProvider.ComputeHash(buffer); return(new DocumentModel( name, context.Operations.Where(t => t.Document == original).ToArray(), original, optimized, buffer, hashProvider.Name, hash)); }
public GraphQLRequest ReadParamsRequest(IQueryCollection parameters) { // next we deserialize the GET request with the query request builder ... string query = parameters[_queryIdentifier]; string queryId = parameters[_queryIdIdentifier]; string operationName = parameters[_operationNameIdentifier]; IReadOnlyDictionary <string, object?>?extensions = null; // if we have no query or query id we cannot execute anything. if (string.IsNullOrEmpty(query) && string.IsNullOrEmpty(queryId)) { // so, if we do not find a top-level query or top-level id we will try to parse // the extensions and look in the extensions for Apollo`s active persisted // query extensions. if ((string)parameters[_extensionsIdentifier] is { Length : > 0 } se) { extensions = ParseJsonObject(se); } // we will use the request parser utils to extract the has from the extensions. if (!TryExtractHash(extensions, _documentHashProvider, out var hash)) { // if we cannot find any query hash in the extensions or if the extensions are // null we are unable to execute and will throw a request error. throw DefaultHttpRequestParser_QueryAndIdMissing(); } // if we however found a query hash we will use it as a query id and move on // to execute the query. queryId = hash; } try { string? queryHash = null; DocumentNode?document = null; if (query is { Length : > 0 }) { byte[] buffer = Encoding.UTF8.GetBytes(query); document = Utf8GraphQLParser.Parse(buffer); queryHash = _documentHashProvider.ComputeHash(buffer); } IReadOnlyDictionary <string, object?>?variables = null; // if we find variables we do need to parse them if ((string)parameters[_variablesIdentifier] is { Length : > 0 } sv) { variables = ParseVariables(sv); } if (extensions is null && (string)parameters[_extensionsIdentifier] is { Length : > 0 } se) { extensions = ParseJsonObject(se); } return(new GraphQLRequest( document, queryId, queryHash, operationName, variables, extensions)); }
public async Task InvokeAsync(IQueryContext context) { if (IsContextIncomplete(context)) { context.Result = QueryResult.CreateError( ErrorBuilder.New() .SetMessage(CoreResources .ParseQueryMiddleware_InComplete) .Build()); } else { Activity activity = _diagnosticEvents.BeginParsing(context); try { bool documentRetrievedFromCache = true; string queryKey = context.Request.QueryName; ICachedQuery cachedQuery = null; if (queryKey is null || context.Request.Query != null) { queryKey = context.Request.QueryHash is null ? _documentHashProvider.ComputeHash( context.Request.Query.ToSource()) : context.Request.QueryHash; } if (context.Request.Query is null && !_queryCache.TryGet(queryKey, out cachedQuery)) { // TODO : check for query storage here? // TODO : RESOURCES context.Result = QueryResult.CreateError( ErrorBuilder.New() .SetMessage("persistedQueryNotFound") .SetCode("CACHED_QUERY_NOT_FOUND") .Build()); return; } if (cachedQuery is null) { cachedQuery = _queryCache.GetOrCreate( queryKey, () => { documentRetrievedFromCache = false; DocumentNode document = ParseDocument(context.Request.Query); return(new CachedQuery(queryKey, document)); }); } // update context context.QueryKey = queryKey; context.CachedQuery = cachedQuery; context.Document = context.CachedQuery.Document; context.ContextData[ContextDataKeys.DocumentCached] = documentRetrievedFromCache; } finally { _diagnosticEvents.EndParsing(activity, context); } await _next(context).ConfigureAwait(false); } }