Creating A SPA Aware Link Within The Quick Navigator When Building A Hybrid Episerver React Application
In this tutorial, you will learn how to create a link within the quick navigator that redirects a content editor to the pages of the current edit mode within Episerver. This article is assuming that you are using .NET to load the page layout and have the server-side quick navigator rendering on the page:
The interesting part of this tutorial is not creating a custom the link within the navigation bar. How to do this has been documented numerous time. The interesting part is hooking a single-page application up with some backend C# code. To combine state-managed within a React.js application - using the Episerver content API - with some backend C#.
When you create a React.js application as the headless solution for Episerver it is likely that you will use React router to manage the routing within the SPA. This makes creating a link in the quick navigator complicated. You can not tell from the current HTTP context what page the user might be viewing.
Having a headless React application that talks to the Episerver context API will require the state to be managed somewhere within the browser. It is likely you would use Redux or potentially React context with a hook. This poses a problem. The code to create a quick navigation link will need to be C# code. The C# code will not be able to access the internal React state.
- A variable on the global window
- Within local storage
Assuming you wanted to use the global window, you could use this:
Granted the code above is slightly hacky. This is the only way to solve this problem if you want to integrate within the Episerver quick navigator. A clean approach might be to create a completely new navigator yourself, however, this will involve more effort. In the code above, first, the editor URL is retrieved using the PageEditing helper. I'm using the RootPage as a placeholder. The page will never link here. you could change this to be anything you want. The actual current page ID will be read in using JS.
In this tutorial, you will learn how to create a higher-order component using React.js that will enable inline editing mode to work within preview mode. This tutorial is part of a series of posts about using Episerver as a headless CMS with React.js. In traditional Episerver MVC rending, using the Propertyfor() helper would traditionally handle wrapping any Episerver component with all the correct attributes to allow the inline editing function to work.
When you use Episerver within a headless context all of the responsibility for making things like getting inline-editing to work is up-to-you. This means it up-to-you to write the frontend to intergrate with Episerver correctly. You will need to apply the the correct attributes on all components.
In order to make inline editing work you will need to decorate every Episerver property with the 'data-epi-edit' attribute when in edit mode. Addding this code onto every compoent would violate the DRY prinicple. When working with React.js the best way to apply this functionailry is with a high-order-component. Explaing what a HOC is and how you can implment it within React is outside the scope of this tutorial, to find more information read this:
The first task to get inline editing to work is to determine if edit-mode is currently enabled for the current request. Let's begin...
How To Get Edit Mode
Within C# you can determine if a request is in edit mode in a few different ways. There are some useful helpers like, 'PageEdititng'. In the music festival site, you can find this code:
The Higher-Order Function
To create a higher-order component code that can be wrapped around a component is fairly simple. The purpose of the HOC is to apply the correct attribute if 'editMode' is enabled. The end HTML that you want to render will need to look something like this - where 'mainContent' is the main of a property of type rich-text:
The code to accomplish this could look like this:
Pass in 'editmode'. Pass in the components name 'mainContent'. The component will be the react component/. For this example, the component would render the rich-text property on a page.
Tips In case Inline Editing Does Not Work
If you want the block preview mode to work you will need to implement a special block preview controller. If you do not know how to do this, then you can find out more in this tutorial, 'How To Preview A Block In Episerver'.
Within the block preview if the attribute is being rendered but inline editing does not work. Using inspector, check the containing element. If the containing element also has the data-epi-edit attribute then this may break inline editing.
In this tutorial, you will learn about some of the APIs that are available when using Episerver as a headless CMS via the content delivery API. Traditionally, when working with Episerver you to render pages and blocks on a website you would use out-of-the-box C# razor helpers to render. In the new world, all pages and blocks are rendered by reading data returned from a JSON API.
To enabled content API, install the Nuget package 'Episerver.ContentDeliveryApi'.
After installing the plug-in, you will need to givethe ContentApiRead role read-access to the homepage and all of its children (assuming the whole site is avaliable to the API). Within the Episerver admin area, under 'Set Access Rights', nsure the ContentApiRead role has 'read' and 'Apply settings for all subitems' are both enabled.
Next, you will either need to create or modify the WebAPi config, like so:
Which will need to be registered within global.ascx:
Next, you will need to configure the API. This can be done within a C# initlisatoin module, like so:
The code above makes the API public so anyone can query it. It also enables a special site definition API. This is useful for debugging at the start. Enabling it will allow you to test that the content API is working. To check the site definition API you can access it like this:
This will return a bunch of data, including siteSettings, language selectors, currencies etc.. If you want to query the API for a specific page or block, you can query it using the content API:
If the content exists, the API will return some corresponding JSON, like so:
In this tutorial, you will learn some performance tips that you can apply to the content API to help improve your website's performance. Recently, I have been working on a React SPA that is powered by the Episerver Content API. As more content was added into the CMS the performance of the content API ground to a halt. Some requests would take over 10 seconds to return. If you looked at the API's response header you will notice the cache-control header is not set by default, as you can see:
One way to fix that is to set the cache headers in the response. Within C# you create an attribute similar to this:
You can register the attribute within a WebApiConfig like this:
Just in case you did not know, you register the WebApiConfig within the 'global.ascx' like so:
Adding this will add the cache headers. this is will help the client, however, you will notice this strange header called 'cf-cache-status: DYNAMIC'.
If you look at the Cloudflare website, here, you can see that dynamic means the resource was not cached by default and your current caching configuration doesn't instruct Cloudflare to cache the resource. How come?
By default, Cloudflare/DXP is configured to only cache content that has a file extension. Assets like images that obviously have file extensions, like a png or a jpg ca be cached easily. If you want Cloudflare to respect the responses cache headers on a page or API request then you will need to Episerver support to create a 'Page Rule' rule for you. The page rule can pattern match on URL so you can rules that specifically target the content API. I suggest you add rules for:
https://www.website.com/api/episerver/v2.0/site?language=en https://www.website.com/?expand=*If the page rule has been set-up correctly you should see a HIT on the cf-cache-status, like so:
Armed with some caching will mean the number of requests that get sent to the origin will be dramatically reduced. You will need to figure out what cache durations you will need to add to the site.
How To Enable Preview Features Using The Content Delivery API
In this tutorial, you will learn how to enable the preview API using Episerver Content Delivery API. Following good API design, the Episerver content delivery API follows API versioning. When communicating with the CSM you will need to decide which version of the API that you would like to use, like so:
As of writing v2 is the latest and greatest of the Content Delivery API. There is however a V3 already on the horizon. If you use Dotpeek to examine the
EPiServer.ContentApi.Cmsassembly within the
ContentApiControlleryou can see a number of s using a variety of versions. By default, the preview routes are no enabled. If you look closely you will see that the
[PreviewFeatureFilter]is applied on all the Preview API end-points
Looking within the attribute you will notice that the
EnablePreviewFeaturesflag is used to determine if a preview API request should be fulfilled. If it is enabled the preview API is allowed. If not a forbidden error will be returned.
To enable the preview API like this:
More information about the content delivery API can be found here. Enjoy!
In this tutorial,l I will evaluate the different ways of calling the content delivery API, evaluating their pros and cons. In this tutorial, I will compare how the music festival and the foundation SPA call the content delivery API. First, let's start with the music festival sample site. If you load the music festival site and look within the network tab, you will see that the call back to the content delivery API uses the same URL as the page itself.
If you look at the response within Chrome you will see that it returns JSON. If you try to view the API call directly within a browser then instead of seeing JSON you the web page will load. This is because the API will only be called when a JSON request is made. If you opened postman and called 'http://music-festival/?expand=*' and setting the 'Accept' header to 'application/json' you will see JSON returned.
This method o using the same URL to access HTML and JSON makes the network requests a little more friendly, however, it doe some with some downsides. First, it makes debugging a pain. If an error occurs on the production site then you will need access to Postman. Next, in terms of caching if you want a warm-up script to cache a range of pages things become a little tricker.
To get around this problem you may be tempted to create an override to allow the JSON to be returned via a normal web request. You could achieve this using an override. You could create a custom
ContentApiRouteService, like this:
You can then register the
CustomContentApiRouteServicewithin StructureMap like this:
If you now pass the query string to the API request the JSON will now be returned:
Armed with a bypass to return JSON from a web request it is easy to warm-up the cache and put expiry headers on the URL. From my experience with building React applications with Episerver, the preview functionality was a bit of a pain to get working when the HTTP and API URLs are the same.
Now let us compare this to how the foundation SPA works. The foundation SPA uses the non-friendly URL to call the API, like this:
This URL is viewable directly from a web browser. No extra code is required to make it viewable from a browser. You will not need to build a
CustomContentApiRouteServiceto access it. In fact within the music festival sample site, if you try to access the API directly it still works:
This means you would have two public-facing URLs to access the same API.
Another consider is multi-language. If you are building a multi-language website you do not need to worry about the language segment. If you need to implement any preview or inline editing then the debugging will be easier. In fact, life becomes a lot easier when you differentiate the API URLs.
The approach you take is obviously up to you. From my experience using the same URL to access HTML and API causes more problems than it solves. Granted the URL is not as friendly when you use API route however when things start to scale the extra confusion and trade-off do not really outweigh the benefits. Granted, either approach will work. If you want to make your life as simple as possible I recommend using the long API path.
In this tutorial, you will learn how to filter out content-type properties that you do not want to be exposed by the content delivery API. When building any website performance matters. Having an end-point that exposes more data that is never used in the app means that the API will request will take longer than it needs to. If you could reduce the payload of every request by 20% then you would notice a big performance gain.
Whether it be a page or a block, when defining content-types within Episerver attributes are used extensively to define meta-data and validations. Out-of-the-box Episerver supports the
JsonIgnoreAttributethat comes with JSON.NET. If you decorate any property on a page or block then it should be filtered out of the content delivery API.
Imagine you were building a new feature and you wanted to hide it behind a feature flag. Within a settings page within the CMS you wanted to decide what was exposed by the API or not. Using this method you could easily provide a dynamic filter on the data that the API exposes. To make it a little more obvious in code that you are doing something different define a custom attribute:
When working with the content delivery API you will likely need some custom logic that tells the pipeline how to serialise the page content into JSON. I recommend extending the
ContentModelMapperBasein order to do this. This is not the only way to define some custom serialization rules. As shown in the music festival sample site, you could create a class that implements the
If you want to limit the properties returned by the content deliver API you can make use of 'ShouldPropertyBeIgnored' within
To extend the method to use a feature flag. You can use the content repository to check if the feature flag setting has been enabled or not.
The data should now be filtered as expected. The code above is very similar to the default behavior and I would only advise going down this route if you want to provide some more advanced property filtering. If you want to check how the default behavior works you can use DotPeek to look within
- Creating A SPA Aware Link Within The Quick Navigator When Building A Hybrid Episerver React Application
- How To Enable Block Preview Inline Editing Using React and Episerver Headless
- Episerver Content Delivery API Introduction
- Improving The Episerver Content APIs Performance With Cache Headers Within DXP
- How To Enable Preview APIs Within The Episerver Content Delivery API
- Episerver Content Deliver API: What URL Should The App Use To Talk To The API?
- How To Filter Out Properties From The Content Deliver API