diff --git a/services/Directory/FilterLists.Directory.Api/CacheControlFilter.cs b/services/Directory/FilterLists.Directory.Api/CacheControlFilter.cs new file mode 100644 index 000000000..c45506758 --- /dev/null +++ b/services/Directory/FilterLists.Directory.Api/CacheControlFilter.cs @@ -0,0 +1,26 @@ +using Microsoft.Net.Http.Headers; + +namespace FilterLists.Directory.Api; + +internal sealed class CacheControlFilter(int clientCacheSeconds, int cdnCacheSeconds) : IEndpointFilter +{ + private readonly string _cacheControlHeaderValue = new CacheControlHeaderValue + { + Public = true, + MaxAge = TimeSpan.FromSeconds(clientCacheSeconds), + SharedMaxAge = TimeSpan.FromSeconds(cdnCacheSeconds) + } + .ToString(); + + public async ValueTask InvokeAsync( + EndpointFilterInvocationContext context, + EndpointFilterDelegate next) + { + var result = await next(context); + + if (context.HttpContext.Response.StatusCode is >= 200 and < 300) + context.HttpContext.Response.Headers.CacheControl = _cacheControlHeaderValue; + + return result; + } +} \ No newline at end of file diff --git a/services/Directory/FilterLists.Directory.Api/Endpoints.cs b/services/Directory/FilterLists.Directory.Api/Endpoints.cs index 69fb53e49..f59131060 100644 --- a/services/Directory/FilterLists.Directory.Api/Endpoints.cs +++ b/services/Directory/FilterLists.Directory.Api/Endpoints.cs @@ -8,6 +8,8 @@ namespace FilterLists.Directory.Api; internal static class Endpoints { + private static readonly CacheControlFilter DefaultGetCacheFilter = new(3600, 86400); + internal static void MapEndpoints(this WebApplication app) { app.MapGet("/languages", async (GetLanguages.Query query, CancellationToken ct) => await query.ExecuteAsync(ct)) @@ -17,7 +19,8 @@ internal static void MapEndpoints(this WebApplication app) Tags = [LanguagesTag], Summary = "Gets the languages targeted by the FilterLists.", OperationId = nameof(GetLanguages) - }); + }) + .AddEndpointFilter(DefaultGetCacheFilter); app.MapGet("/licenses", async (GetLicenses.Query query, CancellationToken ct) => await query.ExecuteAsync(ct)) .Produces>() @@ -26,7 +29,8 @@ internal static void MapEndpoints(this WebApplication app) Tags = [LicensesTag], Summary = "Gets the licenses applied to the FilterLists.", OperationId = nameof(GetLicenses) - }); + }) + .AddEndpointFilter(DefaultGetCacheFilter); app.MapGet("/lists", async (GetLists.Query query, CancellationToken ct) => await query.ExecuteAsync(ct)) .Produces>() @@ -35,7 +39,8 @@ internal static void MapEndpoints(this WebApplication app) Tags = [FilterListsTag], Summary = "Gets the FilterLists.", OperationId = nameof(GetLists) - }); + }) + .AddEndpointFilter(DefaultGetCacheFilter); app.MapGet("/lists/{id:int}", async Task, NotFound>> @@ -64,7 +69,8 @@ internal static void MapEndpoints(this WebApplication app) Example = new OpenApiInteger(1) } ] - }); + }) + .AddEndpointFilter(DefaultGetCacheFilter); app.MapGet("/maintainers", async (GetMaintainers.Query query, CancellationToken ct) => await query.ExecuteAsync(ct)) @@ -74,7 +80,8 @@ internal static void MapEndpoints(this WebApplication app) Tags = [MaintainersTag], Summary = "Gets the maintainers of the FilterLists.", OperationId = nameof(GetMaintainers) - }); + }) + .AddEndpointFilter(DefaultGetCacheFilter); app.MapGet("/software", async (GetSoftware.Query query, CancellationToken ct) => await query.ExecuteAsync(ct)) .Produces>() @@ -83,7 +90,8 @@ internal static void MapEndpoints(this WebApplication app) Tags = [SoftwareTag], Summary = "Gets the software that subscribes to the FilterLists.", OperationId = nameof(GetSoftware) - }); + }) + .AddEndpointFilter(DefaultGetCacheFilter); app.MapGet("/syntaxes", async (GetSyntaxes.Query query, CancellationToken ct) => await query.ExecuteAsync(ct)) .Produces>() @@ -92,7 +100,8 @@ internal static void MapEndpoints(this WebApplication app) Tags = [SyntaxesTag], Summary = "Gets the syntaxes of the FilterLists.", OperationId = nameof(GetSyntaxes) - }); + }) + .AddEndpointFilter(DefaultGetCacheFilter); app.MapGet("/tags", async (GetTags.Query query, CancellationToken ct) => await query.ExecuteAsync(ct)) .Produces>() @@ -101,6 +110,7 @@ internal static void MapEndpoints(this WebApplication app) Tags = [TagsTag], Summary = "Gets the tags of the FilterLists.", OperationId = nameof(GetTags) - }); + }) + .AddEndpointFilter(DefaultGetCacheFilter); } } \ No newline at end of file diff --git a/services/Directory/FilterLists.Directory.Infrastructure/FilterLists.Directory.Infrastructure.csproj b/services/Directory/FilterLists.Directory.Infrastructure/FilterLists.Directory.Infrastructure.csproj index 16cab0f46..c4fe8bfb6 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/FilterLists.Directory.Infrastructure.csproj +++ b/services/Directory/FilterLists.Directory.Infrastructure/FilterLists.Directory.Infrastructure.csproj @@ -6,7 +6,7 @@ - + \ No newline at end of file