SuluHeadlessBundle icon indicating copy to clipboard operation
SuluHeadlessBundle copied to clipboard

Prevent resolving content twice for requests without .json suffix

Open niklasnatter opened this issue 4 years ago • 0 comments

At the moment, if a page that uses the HeadlessWebsiteController is requested without the .json suffix, the controller will render the Twig of the page by reusing the functionality of the Sulu WebsiteController. Additionally, the HeadlessWebsiteController will set the data resolved by the StructureResolver of the bundle to the attributes that are passed to the twig template.

This means, that the content of the page will be resolved two times if it is requested without the .json suffix at the moment.

  1. The HeadlessWebsiteController uses the StructureResolver to resolve the data into the headless format which might be passed to a single page application
  2. The Sulu WebsiteController uses the ParameterResolver to resolve the date into the default format of Sulu which will be compatible with existing templates

This is not a great thing for performance, especially for big pages that are using expensive content types such as smart_content. Unfortunately, I am not sure how to solve this in a flexible manner without neglecting DX. I think there are two relevant usecases of the bundle when thinking about an eventual solution:

1. Using the HeadlessWebsiteController to provide an additional API for external applications

In this case, the bundle is used for providing an additional API for external applications such as mobile apps. The API will not used by the website itself. Instead, pages are still rendered via twig on a .html request. This case is especially common if the bundle is added to an existing project with existing templates.

In this case, the data in the headless format is not used in the twig template and we would not need to call the StructureResolver. One solution for this would be to make the the resolving of this data optional. For example, the HeadlessWebsiteController would only call the StructureResolver if some configuration is set or if the template of the page contains a tag like:

<tag name="sulu_headless.pass_headless_data_to_twig" value="true" />

2. Using the HeadlessWebsiteController with a SPA that is started on the first request

In this case, the .html request renders a minimal HTML document which starts a SPA. To prevent a second request when the SPA is initialized, the data of the page is passed to the SPA from the rendered HTML. Once the SPA is started, it will only make .json requests to gather the content of pages.

In this case, the data in the headless format is used in the twig template to startup the SPA with the correct data. But the data in the default format of sulu is probably not needed. One solution for this would be to provide an additional PureHeadlessWebsiteController that overwrites the getAttributes method of the WebsiteController which would call the ParameterResolver:

class PureHeadlessWebsiteController extends HeadlessWebsiteController
{
    protected function getAttributes($attributes, StructureInterface $structure = null, $preview = false)
    {
        return $attributes;
    }
}

I am a bit sceptic about this solution because it makes the setup of the bundle more complicated. Also, I am not sure if it is worth to solve this case at all, because the twig template will only be rendered on the first request of the user anyway. After the first request, the SPA will only send .json requests.

niklasnatter avatar Nov 27 '20 11:11 niklasnatter