graphql-platform
graphql-platform copied to clipboard
Adds dynamic query cache-control
Allow to annotate the GraphQL schema with caching hints and add middleware that dynamically computes the cache expiration time on a per query basis. In this first iteration these cache hints are used to set the HTTP Cache-Control
header, but I've also did some preparation work for custom user-space cache implementation for example using Redis. However there were some open questions around short-circuiting and cache key computation that were stalling the original PR, so I decided to leave them out.
Closes #2089
Examples
The examples below only show how to apply the @cacheControl
directive on object type fields, but the directive can also be applied on object types, interfaces and union types. If a field returns a type that specifies a @cacheControl
directive, the field will use the cache information from the type, unless the field itself specifies a @cacheControl
directive.
Annotation-based
services.AddGraphQLServer()
.AddHttpQueryCache()
.UseQueryCachePipeline()
.ModifyCacheControlOptions(options =>
{
options.Enable = true;
options.ApplyDefaults = true;
options.DefaultMaxAge = 0;
})
.AddQueryType<Query>();
public class Query
{
[CacheControl(100, Scope = CacheControlScope.Private)]
public string Foo() => "Bar";
}
Code-first
services.AddGraphQLServer()
.AddHttpQueryCache()
.UseQueryCachePipeline()
.ModifyCacheControlOptions(options =>
{
options.Enable = true;
options.ApplyDefaults = true;
options.DefaultMaxAge = 0;
})
.AddQueryType<QueryType>();
public class QueryType : ObjectType
{
protected override void Configure(IObjectTypeDescriptor descriptor)
{
descriptor.Field("foo")
.Resolve("bar")
.CacheControl(100, scope: CacheControlScope.Private);
}
}
Schema-first
services.AddGraphQLServer()
.AddHttpQueryCache()
.UseQueryCachePipeline()
.ModifyCacheControlOptions(options =>
{
options.Enable = true;
options.ApplyDefaults = true;
options.DefaultMaxAge = 0;
})
.AddDocumentFromString(@"
type Query {
foo: String @cacheControl(maxAge: 100 scope: PRIVATE)
}
");
Awesome Tobias, will go through it tonight
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@tobias-tengler Thanks. with this branch, can we try cacheControl directive. It would be great, if any usage snippets added here. Also is this targeted with v13, kindly confirm. thanks.
@tobias-tengler @michaelstaib Thank you. It would be great if this can be targeted to v13
@zf-jsk You can try out the HTTP query cache by registering it like this:
services.AddGraphQLServer()
.AddHttpQueryCache()
.UseQueryCachePipeline()
// optional:
.ModifyCacheControlOptions(options => { })
You can then use the CacheControl()
method in Code-first, the [CacheControl]
attribute in Annotation-based or the @cacheControl
directive in Schema-first to specify rules.
I haven't worked on this in a while, so I'm no longer sure what the current limitations are, but if I remember correctly it should cover basic use cases.
If custom caches are not part of the first iteration then I think this could go into v13. I'll try to spend some time on it to get it usable with HTTP Cache-Control. :)
@tobias-tengler thank you, lets try using it and update here. Awaiting for this feature out. :)
Give me a ping if you need help @tobias-tengler
@michaelstaib Could you check and see if this implementation is alright? If so, please let me know then I can add XML summaries and documentation. This version includes only the HTTP query cache, I've cut out the implementation for reading cached queries from a user-defined storage such as Redis. I think we should wait whether there is interested in having any other caches besides the HTTP cache, before starting to implement the reading portion.
Federated cache directives is a big win. Looking forward to the outcome of this.
~~No clue why it's throwing the The FrameworkReference 'Microsoft.AspNetCore.App' was not recognized
for the Caching.Http project. The csproj looks the same as the AspNetCore project, so I'm not sure where it's coming from. Maybe a .NET 7 thing, but I haven't found anything around it. Maybe one of you knows what's going on here :)~~
Resolved by using AspNetTargetFrameworks
for the HotChocolate.Caching.Http
project.
OK ... will have a look at this
The title of the PR, "Add HTTP query caching" is somewhat misleading. I thought that it was implementing actual response caching. But it does not appear to do that, but instead provides a way to dynamically set the cache-control header.
I find the topic of output caching, with automatic cache invalidation based on mutations, very interesting. However, it appears, we are not quite there yet.
The issue name is more correct