Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • MrFlo 156 posts 400 karma points
    Jul 06, 2022 @ 10:26
    MrFlo
    0

    Custom headless UmbracoApiController which cache system would you recommend ?

    Hi all,

    I've created a simple API for a nodeJS site using custom controllers extended from UmbracoApiController. So a custom headless ?

    I would like to add some caching (no need for dotnut cache as content is the same for all user) and the caching should be invalidated when a Umbraco user has updated some content in Umbraco.

    My methods are only using some content queries.

    What cache system would you recommend for this ?

    Thanks in advance

  • Andrey Karandashov 22 posts 193 karma points c-trib
    Jul 07, 2022 @ 09:11
    Andrey Karandashov
    0

    IPublishedContent is already cached version of content, so not sure why do you need to cache Umbraco content twice. Have you decided to return all the content to your nodejs app? Basically, you can use Umbraco cache and subscribe to "Published" event if you want to clean it up. Here is the article about caching: https://our.umbraco.com/documentation/reference/cache/ https://our.umbraco.com/documentation/reference/cache/applicationcache How to subscribe on published notification: https://our.umbraco.com/documentation/Fundamentals/Code/Subscribing-To-Notifications/

    So, you can cache the content with specific key and if some page is published - you can clear your cache by this key. e.g. "UmbracoContent_{pageKey}", so you will be able to clear it using Umbraco Page Key.

  • MrFlo 156 posts 400 karma points
    Jul 07, 2022 @ 09:22
    MrFlo
    0

    Hi Andrey,

    Thanks for your input. I'm just doing some mapping and some tweaks before returning the results in custom objects. So not all content is returned.

    I wanted to use a simple outputcache, by using a [ResponseCache] attribute and invalidate it on any publish event. I'll look into that.

    Thanks!

  • Keith 56 posts 219 karma points
    1 week ago
    Keith
    1

    Hi @MrFlo

    Unfortunately "outputcache" is not provided by the "[ResponseCache]" attribute. ResponseCache doesnt actually store anything server side. It only adds http response headers, to instruct browsers and CDNs on how to cache the response. So you have no way to "invalidate it on any publish event".

    That being said, setting these headers correctly is still very powerful. I wanted something more flexible than just putting a hard coded decorator on my controllers. So I added cache related properties to my document types and wrote a custom render controller. In the custom render controller, it reads the properties from the current model and changes the response headers accordingly. works well for me so far:

    public override IActionResult Index() 
        {
            var cacheControlHeaderValue = new Microsoft.Net.Http.Headers.CacheControlHeaderValue();
            var ahouldAddHeacher = false;
    
            if (CurrentPage.HasProperty("clientCacheMaxAge") && CurrentPage.HasValue("clientCacheMaxAge") && CurrentPage.Value<int>("clientCacheMaxAge") > 0)
            {
                ahouldAddHeacher = true;
                cacheControlHeaderValue.MaxAge = TimeSpan.FromSeconds(CurrentPage.Value<int>("clientCacheMaxAge"));
            }
    
            if (CurrentPage.HasProperty("clientCachePublic") && CurrentPage.Value<bool>("clientCachePublic"))
            {
                ahouldAddHeacher = true;
                cacheControlHeaderValue.Public = true;
            }
    
            if (CurrentPage.HasProperty("clientCachePrivate") && CurrentPage.Value<bool>("clientCachePrivate"))
            {
                ahouldAddHeacher = true;
                cacheControlHeaderValue.Private = true;
            }
    
            if (CurrentPage.HasProperty("clientCacheNoStore") && CurrentPage.Value<bool>("clientCacheNoStore"))
            {
                ahouldAddHeacher = true;
                cacheControlHeaderValue.NoStore = true;
            }
    
            if (ahouldAddHeacher)
            {
                Response.GetTypedHeaders().CacheControl = cacheControlHeaderValue;
            }
    
            return base.Index();
        }
    

    To achieve server side caching, I used the <Cache> tag in my razor pages, but for custom APIs, I used Redis.

    I needed to invalidate the cache when certain document types were published. To achieve this, I created a published handler, that adds a date to the cache for each content type alias saved:

        public class ContentPublishedHandler : INotificationAsyncHandler<ContentPublishedNotification>
    {
        private readonly IDistributedCache cache;
    
        public ContentPublishedHandler(IDistributedCache cache)
        {
            this.cache = cache;
        }
    
        public Task HandleAsync(ContentPublishedNotification notification, CancellationToken cancellationToken)
        {
            return Task.WhenAll(notification.PublishedEntities.Select(node => cache.SetStringAsync(node.ContentType.Alias + "LastPublished", DateTime.Now.Ticks.ToString())));
        }
    }
    

    Then when generating a cache key I can do something this:

    var lastPublished = await distributedCache.GetStringAsync("BlogLastPublished");
    var latestBlogsCacheKey = "LatestBlogs" + lastPublished;
    var latestBlogs = await distributedCache.GetStringAsync(latestBlogsCacheKey );
    

    This is all heavily modified to illustrate the point... but the idea is that before I go generating a response for a particular content type, I query the redis cache. And part of the key I use in that query is the last published date of the content type I am querying.

    Takes 2 calls to redis, but it seems to work pretty well.

  • MrFlo 156 posts 400 karma points
    1 week ago
    MrFlo
    0

    Hi @Keith, thanks for your clear and informative reply! Redis seems indeed a good solution 👍 Do you know what they use in Umbraco headless?

  • Biagio Paruolo 1522 posts 1666 karma points c-trib
    1 week ago
    Biagio Paruolo
    0

    How Do you protect the API with OAUTH?

Please Sign in or register to post replies

Write your reply to:

Draft