diff --git a/src/Umbraco.Cms.Api.Delivery/Caching/DeliveryApiOutputCachePolicy.cs b/src/Umbraco.Cms.Api.Delivery/Caching/DeliveryApiOutputCachePolicy.cs index da1580554cbb..2c626d0bfb4a 100644 --- a/src/Umbraco.Cms.Api.Delivery/Caching/DeliveryApiOutputCachePolicy.cs +++ b/src/Umbraco.Cms.Api.Delivery/Caching/DeliveryApiOutputCachePolicy.cs @@ -1,5 +1,6 @@ -using Microsoft.AspNetCore.OutputCaching; +using Microsoft.AspNetCore.OutputCaching; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Primitives; using Umbraco.Cms.Core.DeliveryApi; namespace Umbraco.Cms.Api.Delivery.Caching; @@ -7,9 +8,13 @@ namespace Umbraco.Cms.Api.Delivery.Caching; internal sealed class DeliveryApiOutputCachePolicy : IOutputCachePolicy { private readonly TimeSpan _duration; + private readonly StringValues _varyByHeaderNames; - public DeliveryApiOutputCachePolicy(TimeSpan duration) - => _duration = duration; + public DeliveryApiOutputCachePolicy(TimeSpan duration, StringValues varyByHeaderNames) + { + _duration = duration; + _varyByHeaderNames = varyByHeaderNames; + } ValueTask IOutputCachePolicy.CacheRequestAsync(OutputCacheContext context, CancellationToken cancellationToken) { @@ -20,6 +25,7 @@ ValueTask IOutputCachePolicy.CacheRequestAsync(OutputCacheContext context, Cance context.EnableOutputCaching = requestPreviewService.IsPreview() is false; context.ResponseExpirationTimeSpan = _duration; + context.CacheVaryByRules.HeaderNames = _varyByHeaderNames; return ValueTask.CompletedTask; } diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByRouteContentApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByRouteContentApiController.cs index f60fa442651b..7120553fb17e 100644 --- a/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByRouteContentApiController.cs +++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByRouteContentApiController.cs @@ -19,7 +19,7 @@ public class ByRouteContentApiController : ContentApiItemControllerBase private readonly IRequestRedirectService _requestRedirectService; private readonly IRequestPreviewService _requestPreviewService; private readonly IRequestMemberAccessService _requestMemberAccessService; - private const string PreviewContentRequestPathPrefix = $"/{Constants.DeliveryApi.Routing.PreviewContentPathPrefix}"; + private const string PreviewContentRequestPathPrefix = $"/{Umbraco.Cms.Core.Constants.DeliveryApi.Routing.PreviewContentPathPrefix}"; [Obsolete($"Please use the constructor that does not accept {nameof(IPublicAccessService)}. Will be removed in V14.")] public ByRouteContentApiController( diff --git a/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs index 20141f210853..48399a62e3f1 100644 --- a/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Primitives; using Umbraco.Cms.Api.Common.DependencyInjection; using Umbraco.Cms.Api.Delivery.Accessors; using Umbraco.Cms.Api.Delivery.Caching; @@ -108,12 +109,20 @@ private static IUmbracoBuilder AddOutputCache(this IUmbracoBuilder builder) if (outputCacheSettings.ContentDuration.TotalSeconds > 0) { - options.AddPolicy(Constants.DeliveryApi.OutputCache.ContentCachePolicy, new DeliveryApiOutputCachePolicy(outputCacheSettings.ContentDuration)); + options.AddPolicy( + Constants.DeliveryApi.OutputCache.ContentCachePolicy, + new DeliveryApiOutputCachePolicy( + outputCacheSettings.ContentDuration, + new StringValues([Constants.DeliveryApi.HeaderNames.AcceptLanguage, Constants.DeliveryApi.HeaderNames.StartItem]))); } if (outputCacheSettings.MediaDuration.TotalSeconds > 0) { - options.AddPolicy(Constants.DeliveryApi.OutputCache.MediaCachePolicy, new DeliveryApiOutputCachePolicy(outputCacheSettings.MediaDuration)); + options.AddPolicy( + Constants.DeliveryApi.OutputCache.MediaCachePolicy, + new DeliveryApiOutputCachePolicy( + outputCacheSettings.MediaDuration, + Constants.DeliveryApi.HeaderNames.StartItem)); } }); diff --git a/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs b/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs index 0d2d35fb2399..748033e4a25f 100644 --- a/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs +++ b/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using Umbraco.Cms.Api.Delivery.Configuration; @@ -21,7 +21,7 @@ protected override void ApplyOperation(OpenApiOperation operation, OperationFilt operation.Parameters.Add(new OpenApiParameter { - Name = "Accept-Language", + Name = Core.Constants.DeliveryApi.HeaderNames.AcceptLanguage, In = ParameterLocation.Header, Required = false, Description = "Defines the language to return. Use this when querying language variant content items.", @@ -37,7 +37,7 @@ protected override void ApplyOperation(OpenApiOperation operation, OperationFilt operation.Parameters.Add(new OpenApiParameter { - Name = "Preview", + Name = Core.Constants.DeliveryApi.HeaderNames.Preview, In = ParameterLocation.Header, Required = false, Description = "Whether to request draft content.", @@ -46,7 +46,7 @@ protected override void ApplyOperation(OpenApiOperation operation, OperationFilt operation.Parameters.Add(new OpenApiParameter { - Name = "Start-Item", + Name = Core.Constants.DeliveryApi.HeaderNames.StartItem, In = ParameterLocation.Header, Required = false, Description = "URL segment or GUID of a root content item.", diff --git a/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerDocumentationFilterBase.cs b/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerDocumentationFilterBase.cs index 52acddaca960..8a450a2f9b97 100644 --- a/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerDocumentationFilterBase.cs +++ b/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerDocumentationFilterBase.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; @@ -63,7 +63,7 @@ protected void AddFields(OpenApiOperation operation, OperationFilterContext cont protected void AddApiKey(OpenApiOperation operation) => operation.Parameters.Add(new OpenApiParameter { - Name = "Api-Key", + Name = Core.Constants.DeliveryApi.HeaderNames.ApiKey, In = ParameterLocation.Header, Required = false, Description = "API key specified through configuration to authorize access to the API.", diff --git a/src/Umbraco.Cms.Api.Delivery/Services/ApiAccessService.cs b/src/Umbraco.Cms.Api.Delivery/Services/ApiAccessService.cs index 0ba7df9b4932..0a581af9f59f 100644 --- a/src/Umbraco.Cms.Api.Delivery/Services/ApiAccessService.cs +++ b/src/Umbraco.Cms.Api.Delivery/Services/ApiAccessService.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DeliveryApi; @@ -29,7 +29,7 @@ public ApiAccessService(IHttpContextAccessor httpContextAccessor, IOptionsMonito private bool IfEnabled(Func condition) => _deliveryApiSettings.Enabled && condition(); private bool HasValidApiKey() => _deliveryApiSettings.ApiKey.IsNullOrWhiteSpace() == false - && _deliveryApiSettings.ApiKey.Equals(GetHeaderValue("Api-Key")); + && _deliveryApiSettings.ApiKey.Equals(GetHeaderValue(Core.Constants.DeliveryApi.HeaderNames.ApiKey)); private bool IfMediaEnabled(Func condition) => _deliveryApiSettings is { Enabled: true, Media.Enabled: true } && condition(); } diff --git a/src/Umbraco.Cms.Api.Delivery/Services/RequestPreviewService.cs b/src/Umbraco.Cms.Api.Delivery/Services/RequestPreviewService.cs index f891aee6894f..25689125f538 100644 --- a/src/Umbraco.Cms.Api.Delivery/Services/RequestPreviewService.cs +++ b/src/Umbraco.Cms.Api.Delivery/Services/RequestPreviewService.cs @@ -11,5 +11,5 @@ public RequestPreviewService(IHttpContextAccessor httpContextAccessor) } /// - public bool IsPreview() => string.Equals(GetHeaderValue("Preview"), "true", StringComparison.OrdinalIgnoreCase); + public bool IsPreview() => string.Equals(GetHeaderValue(Core.Constants.DeliveryApi.HeaderNames.Preview), "true", StringComparison.OrdinalIgnoreCase); } diff --git a/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs b/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs index dd72d930bdbe..f3169e1a75b4 100644 --- a/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs +++ b/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs @@ -58,5 +58,5 @@ public RequestStartItemProvider( } /// - public string? RequestedStartItem() => GetHeaderValue("Start-Item"); + public string? RequestedStartItem() => GetHeaderValue(Constants.DeliveryApi.HeaderNames.StartItem); } diff --git a/src/Umbraco.Core/Constants-DeliveryApi.cs b/src/Umbraco.Core/Constants-DeliveryApi.cs index 85677a23bc55..35d8513fa7cc 100644 --- a/src/Umbraco.Core/Constants-DeliveryApi.cs +++ b/src/Umbraco.Core/Constants-DeliveryApi.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Cms.Core; +namespace Umbraco.Cms.Core; public static partial class Constants { @@ -24,14 +24,42 @@ public static class Routing public static class OutputCache { /// - /// Output cache policy name for content + /// Output cache policy name for content. /// public const string ContentCachePolicy = "DeliveryApiContent"; /// - /// Output cache policy name for media + /// Output cache policy name for media. /// public const string MediaCachePolicy = "DeliveryApiMedia"; } + + /// + /// Constants for Delivery API header names. + /// + public static class HeaderNames + { + /// + /// Header name for accept language. + /// + public const string AcceptLanguage = "Accept-Language"; + + /// + /// Header name for API key. + /// + public const string ApiKey = "Api-Key"; + + /// + /// Header name for preview. + /// + public const string Preview = "Preview"; + + /// + /// Header name for start item. + /// + public const string StartItem = "Start-Item"; + + + } } }