JasperFx / wolverine

Supercharged .NET server side development!
https://wolverinefx.net
MIT License
1.27k stars 139 forks source link

Ability to easily and cleanly add caching headers to the response. (Wolverine.HTTP) #1125

Open BossByz opened 2 weeks ago

BossByz commented 2 weeks ago

Is your feature request related to a problem? Please describe. There are workarounds for this, however it could be better to have a wolverine feature for it.

Describe the solution you'd like An easy and clean way to apply caching in response headers. Maybe an attribute? Extension methods on wolverine http methods?

Describe alternatives you've considered Extension methods to IResult to apply httpContext.Response.Headers.CacheControl. Have also tried middleware to apply caching but struggled getting a parameter passed in for the cache duration etc. Each endpoint should ideally have its own caching options, or maybe having global profiles will also help for those endpoints that just need the general cache time applied.

Additional context Here is an example of a basic setup. (Can ignore the fusion cache part, this is just for less calls to the database/ handler logic). We are looking for less calls to the API itself:

public class TestEndpoint
{
    [Tags("Test")]
    [WolverineGet("/Test")]
    public async Task<IResult> TestGet(IMessageBus messageBus, IFusionCache cache, ILogger<TestEndpoint> logger,
        int num,
        HttpContext context,
        CancellationToken cancellationToken = default)
    {
        var record = await cache.GetOrSetAsync($"test{context.Request.GetDisplayUrl()}",
            _ => messageBus.InvokeAsync<object>(new TestRecord(num), cancellationToken), token: cancellationToken);

        return Results.Ok(record).WithCacheControl(PrivateMaxAge10Seconds);
    }
}
public static class WolverineResponseCachingExtensions
{
    public static IResult WithCacheControl(this IResult result, CacheControlHeaderValue cacheControl)
    {
        return new CachedResult(result, cacheControl);
    }
}
public static class CacheControlConstants
{
    public static readonly CacheControlHeaderValue PrivateMaxAge10Seconds = new()
    {
        Private = true,
        MaxAge = 10.Seconds()
    };
}
public class CachedResult(IResult innerResult, CacheControlHeaderValue cacheControl) : IResult
{
    public Task ExecuteAsync(HttpContext httpContext)
    {
        httpContext.Response.GetTypedHeaders().CacheControl = cacheControl;
        return innerResult.ExecuteAsync(httpContext);
    }
}

Thanks for reading :)