Copied to clipboard

Flag this post as spam?

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


  • Adam Gärdelöv 8 posts 80 karma points
    Oct 14, 2022 @ 13:22
    Adam Gärdelöv
    1

    Best approach to build Umbraco CMS Headless (Without Heartcore)

    Hi!

    I'm about to start work on building a new site with Umbraco CMS Headless. And unfortunately the customer have chosen not to use Heartcore.

    The plan is to have a Next.JS frontend hosted separately. I understand that there are a couple of different plugins to make Umbraco CMS Headless. But before I start this work I wanted to check with you which way you think is preferable?

    Adam

  • Marcio Goularte 388 posts 1360 karma points
    Oct 14, 2022 @ 18:50
    Marcio Goularte
    0

    Hi, the only alternative I know is to implement API. When I needed to do it I used this repository as a reference

    https://github.com/deMD/UmbracoContentApi

  • Roy Berris 89 posts 577 karma points c-trib
    Oct 17, 2022 @ 07:22
    Roy Berris
    2

    Hi, this is quite an interesting topic. Some of my colleagues have actually build this. I am not allowed to share code, but I can tell you about the approach.

    You'll need to build your own API, which is not that much work.

    The CMS has its own data structure. Doctypes, etc. We do not want to give these structures to an API one-on-one. We'll need to convert every doctype to its own DTO.

    There are two approached to this which we used:

    • Create a mapper that maps every full doctype to a DTO class. Your HomePage will have a HomePageDto. It's a one-on-one map (using a mapping strategy). This gives you great control but it's a lot of work.
    • Second approach is to map each data type to a primitive type. This way you convert whole doctypes to JSON models without writing any specific code. This gives less control, but you can build an approach where you can override certain doctypes. Of course, you'll also need a system on which properties to convert. Again, you don't want the whole doctype to convert to JSON, but rather a set of.

    First approach is easier, more on implementation. Second approach is powerful but abstract. Both have their pro's and con's.

    Getting the content is also not that hard. You should just map to the CMS provided URL. IPublishedContentCache has a method GetByRoute. Accessible through the IUmbracoContext.

    A headless front-end does not build the pages like MVC does. You should split some components into their own calls. For example, the header, footer and menu are likely to be their own components. Which you can 'refresh' with the API if you have page specific implementation.

    Another topic would be list items. A blog overview page has a list of blog posts. How you would get that list of blog posts is really different from a MVC approach. You'll probably want to get the blog overview page on its own, which has an indicator that it is an overview page of type blog. Then get a paginated list of blogs on its own. Separate calls to the API.

    With the NuCache, and also some cache of your own this is very fast (Umbraco 10). I recommend caching the DTO's that you have converted from published content for example. So, the API does not convert it on every call.

    You should also get the translations dictionary to the front-end. We discussed this and our thoughts on this is to get the full dictionary on 'startup' of your front-end. (Or lazy when getting the first item, but the first item is likely to be on the homepage. It's on 'startup' anyway). You really don't want to make an API call for every dictionary item that you need to get.

    We build all this using the CLEAN architecture principles to make every component swappable, which proved itself when upgrading Umbraco or just switching out caching systems etc. I believe this repo was used as a big influencer on the software design. https://github.com/jasontaylordev/CleanArchitecture

    These are just some topics that we touched, not everything to build a good headless version of Umbraco on the Core product. And probably not the best approach once Umbraco comes with its own version of the headless API in Core. But we'll see it when the time comes

  • Adam Gärdelöv 8 posts 80 karma points
    Oct 25, 2022 @ 07:03
    Adam Gärdelöv
    0

    Hi Roy and thanks for the good answer! Would it be possible for you to explain how you mapped your doctypes to DTOs?

  • Roy Berris 89 posts 577 karma points c-trib
    Oct 26, 2022 @ 07:26
    Roy Berris
    0

    Hi,

    I used something we called a Strategy (Mapping strategy).

    public interface IStrategy<T> where T : IPublishedContent
    {
        public Task<IViewModel> Map(T content);
    }
    

    If we have a homepage to map it would look something like

    public class HomePageStrategy : IStrategy<HomePage>
    {
        public async Task<IViewModel> Map(HomePage content)
        {
             var viewModel = new HomePageViewModel();
             // ...
             return viewModel;
        }
    }
    

    Now register these strategies in the DI container. You can do this with reflection.

    From a "DefaultRenderController" get the type of the IPublishedContent in the published request and inject the IStrategy<T> which matches the type (again reflection).

    Nice thing about this is, is that you can have one view model (dto) which have multiple document types.

    For example every website has an overview page with paginated results. This can be represented with:

    public class OverviewPageDto
    {
          public string Title { get; set; }
    
          public IList<IListItem> Items { get; set; }
    }
    

    IListItem can again be the same concept as your IViewModel where you'll have a strategy for each of the document types that can be represented in an overview page.

    public class CardModel : IListItem
    {
        public string Title { get; set; }
    
        public string Description { get; set; }
    
        public ImageModel Thumbnail { get; set; }
    
        public LinkModel PageUrl { get; set; }
    }
    

    Now you can create a strategy that maps every overview page type to OverviewPageDto. BlogOverviewPage, NewsOverviewPage, ArticleOverviewPage, ....

    FE writes implementation once (if done right) and we can throw (from a backend perspective) any doctype at it.

  • Adam Gärdelöv 8 posts 80 karma points
    Oct 26, 2022 @ 08:57
    Adam Gärdelöv
    0

    Great answer again! And in the different mapping strategies you set all the properties manually by getting umbraco content?

     var viewModel = new StartPageViewModel
     {
            Title = content.GetProperty("title")?.GetValue()?.ToString() ?? string.Empty
     };
    
  • Roy Berris 89 posts 577 karma points c-trib
    Oct 27, 2022 @ 13:53
    Roy Berris
    0

    Yes, or use the ModelsBuilder type.

  • Adam Gärdelöv 8 posts 80 karma points
    Oct 27, 2022 @ 13:55
    Adam Gärdelöv
    0

    Yes i decided to use ModelsBuilder. Thanks for the help. Not used to Umbraco :)

Please Sign in or register to post replies

Write your reply to:

Draft