Optimizely Graph - best practices for business logic?

Vote:
 

I am building a headless website in CMS12 and the new Optimizely Graph.

When building a traditional MVC website we had the power of C# and the powerful Episerver SDK at our disposal within the page controllers, so that we can apply business logic and filtering, before passing data to the frontend. 

For example, let's say I want to fetch the website navigation with a simple GraphQL query, for rendering on the frontend

{
  ContentPage(where: {VisibleInMenu: {eq: true}}) {
    items {
      Name,
      Url
    }
  }
}

That all works fine, however, if I'm building a mega-menu in the frontend for example, I need to to know what pages are "top-level", and what pages sit underneath each item. In a traditional architecture I would construct a ViewModel with this information in the controller, however, we don't have that capability with Optimizely Graph.

So my question is, for this scenario, what is the best practice to tackle it?

- Do I include the page children in the request and delegate the filtering to the frontend?

- Or is there a way to add custom resolvers? I couldn't see it in the docs, but if not, are there plans for this, or any plans to give us more server-side control?

Thanks

#321544
Edited, May 05, 2024 14:48
James Wilkinson - May 07, 2024 8:42
To add some further context for anyone who might have similar troubles, the OP is based on a headless architecture that follows the Optimizely Music festival example, which has the GraphQL queries constructed directly within the frontend itself.

The accepted answer here suggests following a different approach by using a BFF.
Vote:
 

Hi James,

I do not think that we should use Optimizely Graph for this case. You can consider to create new api to return mega menu model with sub-items. You can use IContentLoader to retrieve menu items automatically from decendants of start page. Of couse, we could define maximum level of mega menu to get only necessary items.

If you still want to use Optimezely Graph then I suggest that you can return more info in response such as parent link or ancestors and rendering mega menu level based on this data

#321582
May 06, 2024 8:25
James Wilkinson - May 06, 2024 8:43
Okay so we are already using Optimizely Graph in other places. So correct me if wrong, but you suggest create a custom endpoint specifically for this scenario, which would mean the frontend has a 'hybrid' approach, some elements from graph and some elements from our custom endpoint?
Binh Nguyen Thi - May 06, 2024 9:01
Hi,
I do not realize that you only use Optimizely Graph in front-end site. I thought that you may use another one such as service api or something else for authentication for example.
So yes, if creating a custom endpoint for tihss scenario then it means that the front-end has a "hybrid" approach for consuming data via api.
If you do not have plan to use "hybrid" then you can think another one to solve your problem is adding more parent link / ancestors in Graph request.
I think parent link/ancestors is indexed in Graph cloud by default. If you want to add custom fields into indexed model then you can use Extension method like this https://world.optimizely.com/blogs/manh-nguyen/dates/2024/4/optimizely-graph-client-dealing-with-cms-data-models-for-query-builder/
Vote:
 

Not sure I agree with this statement "I would construct a ViewModel with this information in the controller, however, we don't have that capability with Optimizely Graph.". Why can't you construct a view model in the frontend (or whereever you're making this graph call)?

"Do I include the page children in the request and delegate the filtering to the frontend?" Yes, include as much as you need in your query to graph.

#321585
May 06, 2024 9:04
Vote:
 

Hi Johan, the context of that statement was from a backend point-of-view. I'm quite new to headless architecture so I'm trying to piece this together currently.

So what you're saying for this scenario, the correct practice would be to pass all of the data into the frontend and apply the filtering and business logic there? 

I was just wondering if there was a way to intercept the queries in the backend to make them slightly more efficient, e.g. a custom resolver to intercept the request and add some further context to the response serving the frontend, to make the frontend logic a little less complex. 

It would be much easier to write some C# backend code to include a node called "IsTopLevelItem" for example. 

#321591
Edited, May 06, 2024 11:45
Vote:
 

"So what you're saying for this scenario, the correct practice would be to pass all of the data into the frontend and apply the filtering and business logic there?" That's not what I'm saying. Still a bit unclear to me if you're actually have a headless setup or just making API calls from client-side? You can still have a backend even though you're running your application headless, it can be C#, Node.js or anything, but it's not hosted by the same application as the CMS then. This is often referred to as having a Backend For Frontend (BFF). Headless means that your application is not hosted by the CMS application. Are you still able to deploy code to the CMS application? If yes, then put logic there and expose it via Web API endpoints if you don't find Graph to cover what you need. Then you can use the built-in APIs and Graph. 

#321592
Edited, May 06, 2024 12:02
Vote:
 

We are striving for a headless setup yes, but if it's true that the rules of headless mean that the backend code should be seperate from CMS, then that's where things get a little complicated.

A backend is still needed for CMS when using Optimizely Graph for headless, because it's needed for defining the content models for pages and blocks. 

Yes, we are able to deploy code to CMS - we're running a base CMS12 solution with the Optimizely Graph add-on, so we have the full capabilities of .net core.

It just doesn't feel right to go with a hybrid approach of creating a custom endpoint for this scenario, whilst also having other scenarios as GraphQL queries, as things will start to get messy.

(...and especially if it's true that Backend code should be seperate from CMS).

#321593
Edited, May 06, 2024 12:22
Vote:
 

If you don't want to add code and endpoints in the CMS application, then create a separate backend (BFF) and host it together with the frontend. You'll most likely need it in the end anyway, e.g. for server-side renderinging or React Server Components.

#321595
Edited, May 06, 2024 12:32
Vote:
 

Thanks Johan, having re-read your comments, I think that makes sense actually.

So in terms of the flow, it would be something like:

Frontend -> BFF -> GraphQL -> CMS

That would definitely clean things up for us. 

#321597
May 06, 2024 12:46
Vote:
 

"A backend is still needed for CMS when using Optimizely Graph for headless, because it's needed for defining the content models for pages and blocks." Not entirely true. You can model via the UI or API as well. Some things are however only possible via content models, as-of-now.

#321598
May 06, 2024 12:47
James Wilkinson - May 06, 2024 12:51
yeah idd. I know you guys are working hard to change that with the new saas stuff, but its a bit of an awkward transition period we're sitting in at the moment !
Vote:
 

I think Johan has already done a great job to explain that. 

As he mentioned, BFF will be needed at somepoint. From a good architecture perspective, you'd better to start with BFF as mandatory instead of create a bounch of silos api calls in the client app first to get job done for now.

Think about if you get charge in API calls, rate limit etc, it's not going to work by spreading api calls over the client app. Move to headless is a conceptual change. Instead of poking around how to build shaped data using CMS related SDK, you end up by composing APIs in BFF (can be via RESTful or Graphql). For business application developer, you don't even know what provides the data behind (it could be cms, elastic, nosql etc). The most common and easy way to start BFF is using cloud service like Azure Function / AWS lambda. 

#321638
May 07, 2024 2:18
James Wilkinson - May 07, 2024 8:34
Thank you for the insights Vincent, and good idea about Azure functions as that would make it much easier to scale.
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.