Skip to content

Conversation

@kjac
Copy link
Contributor

@kjac kjac commented Mar 21, 2024

Prerequisites

  • I have added steps to test this contribution in the description below

Description

In certain cases it would be nice to be able to customise the content paths returned by the Content Delivery API - for example if one has a collection of shared content that is reused between multiple roots (sites).

This PR introduces the content path provider and the matching content path resolver. Think of these as URL Provider and Content Finder for the Content Delivery API here.

The core implementations (ApiContentPathProvider, ApiContentPathResolver) are left public and unsealed to enable extendability.

Testing this PR

Consider a content structure like this:

image

The following code adds custom paths to "Root One" and everything below (prefixes the content path with /my-path):

using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;

namespace Umbraco.Cms.Web.UI.Custom;

public class MyApiContentPathComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
        => builder.Services
            .AddSingleton<IApiContentPathProvider, MyApiContentPathProvider>()
            .AddSingleton<IApiContentPathResolver, MyApiContentPathResolver>();
}

public class MyApiContentPathProvider : ApiContentPathProvider
{
    public MyApiContentPathProvider(IPublishedUrlProvider publishedUrlProvider)
        : base(publishedUrlProvider)
    {
    }

    public override string? GetContentPath(IPublishedContent content, string? culture)
    {
        var path = base.GetContentPath(content, culture);
        if (path.IsNullOrWhiteSpace() is false && content.Root().Name == "Root One")
        {
            path = $"/my-path{path.EnsureStartsWith('/')}";
        }

        return path;
    }
}

public class MyApiContentPathResolver : ApiContentPathResolver
{
    public MyApiContentPathResolver(
        IRequestRoutingService requestRoutingService,
        IApiPublishedContentCache apiPublishedContentCache)
        : base(requestRoutingService, apiPublishedContentCache)
    {
    }

    public override IPublishedContent? ResolveContentPath(string path)
        => base.ResolveContentPath(path.TrimStart("/my-path"));
}

This should yield custom paths for published content in the Content Delivery API output

image

...while unpublished content retains the default preview path (remember to supply an API key to fetch unpublished content):

image

It should be possible to request the content by the custom path:

image

...and unpublished content by the preview path:

image

@bergmania
Copy link
Member

Code looks good, but I have a few concerns after testing.

  1. I am still able to use the original path to get a content, while I have your custom code in use.

  2. When using your custom code, conflicts are not detected, and it is possible to "hide" other contnet

image image

@kjac
Copy link
Contributor Author

kjac commented Mar 22, 2024

Code looks good, but I have a few concerns after testing.

  1. I am still able to use the original path to get a content, while I have your custom code in use.
  2. When using your custom code, conflicts are not detected, and it is possible to "hide" other contnet

Yeah. Those two are very much two sides of the same coin. And we can't do much about it at core level, at least not without sacrificing a whole lot of performance for everyone utilizing the Delivery API (custom path provider/resolver or not).

I would honestly be surprised if it would ever become a problem in the wild. And if so, people implementing custom providers and resolvers are free to build in whatever stringent rules they might want to apply.

@bergmania bergmania merged commit b1c3473 into v13/dev Mar 22, 2024
@bergmania bergmania deleted the v13/feature/content-api-path-provider branch March 22, 2024 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants