This week I found the time to experiment more with my Umbraco 9 Demo Site, and this time I wanted to build the products section that most Umbracians are familiar with from the original demo site from version 8.
Same same, but different
However, I wanted to do things a little different instead of just copy pasting from the v8 demo site to mine.
See for most of the client projects that I’ve worked on, products doesn’t necessary live in Umbraco as individual content items.
Most clients has thousands of products that we dont want to import in to Umbraco and having to update on some sort of schedule.
Instead, we want to render product from an external source (like an API or separate datebase) directly on the website (with some caching of course to avoid having to call the API on every page reload).
This has now been implemented and you can check it out on GitHub, but I thought I would walk through the solution in this blogpost. As you'll notice this is not a tutorial but rather a summary of the different parts needed.
Creating a Products container
The first thing we need is some sort of container that will serve as the root page for all the products.
In my example this is a super simple page, but in a real-world example it would probably have a bunch of searching, filtering etc. But for now, let’s keep it simple.
Setting up the integration project
I usually like to keep all my integrations in a separate project, this way I know that everything needed for that integration can be found in that one place.
Also if any of my other projects in the solution needs to access this integration it has a minimal library to reference and use instead of having to rely on any Umbraco dependencies.
In this example site I have just hardcoded the product results in the ProductService, this would of course be replaced in a real-world project and you also probably need to add some caching so you dont stress the API to much. But again, let’s keep it simple for now.
Rendering the product listing
My products container has a RenderController that is calling the product service and populating a list in the container view model.
And then in the view we are just iterating through all our external products and render them as linked preview boxes.
Rendering a product page
The URL for each products is formatted using this pattern /(name of container)/(product ID)/(product name). The product name is just there for show, it looks a lot better than just having /products/123.
Instead we get URL:s that looks like: /products/6/jumpsuit.
The next thing we need is a ContentFinder, that extracts this product ID from the URL and tries to find a product with that ID from our external source.
If the ID does not exist, we will get a 404 page, as expected. But if the product exists, we will get a result.
In my example I set the IPublishedContent property of the request to the container page. There are other ways you can solve this. You can create a fake IPublishedContent item based on the product data and set in the ContentFinder. You could also have a child page under the container (example ProductPage) which will work as a placeholder for all your products.
But in my example I took the easiest and quickest solution, which was setting the IPublishedContent to my container.
Disclaimer: In all honesty this mentioned placeholder would probably be much cleaner in terms of separating logic, but for my little demo there where so little logic needed for the product page so I just went with the same controller for now. Might be refactored in the future.
And the last thing I do is because I have set the IPublishedContent to my container page, Umbraco will route my request to my container controller. If you would have created a ProductPage placeholder like I mentioned, you would have had to create a separate controller dedicated for this request.
Anyways, this is what the end result looks like:
So there we have it. Product rendered from an external source, not living in Umbraco but still rendered as if it was. Hope it can help someone somewhere, I had a lot of fun doing it.
I also added some Unit Testing for the ContentFinder that can be found here.
Take care of each other.