Add wrapper to Views Rest JSON Output I am rebuilding an API in Drupal. The structure of the JSON must remain the same.

I am using Views and Draggable Views so the user can order items on an overview page. I Enabled the view for exporting REST JSON.

The response JSON must have a structure like this

{
  items: [{...},{...}]
}


But currently views output is like this

{[{...},{...}]}


I already managed to get my desired output without views and a special export controller but unfortunately, I need draggable views in additions to views.
I also managed to create nested structures with Entity Normalizers inside an item but I want the whole output of the view is wrapped in "items".
Any help would be appreciated.
You can write a views style plugin to get through this fast. Here is an example of that, which adds an outer wrapper of results plus a totalCount item:

&lt;?php

namespace Drupal\mymodule\Plugin\views\style;

use Drupal\rest\Plugin\views\style\Serializer;

/**
 * The style plugin for serialized output formats.
 *
 * @ingroup views_style_plugins
 *
 * @ViewsStyle(
 *   id = "serializer_count",
 *   title = @Translation("Serializer with Count"),
 *   help = @Translation("Serializes views row data using the Serializer component and adds a count."),
 *   display_types = {"data"}
 * )
 */
class SerializerCount extends Serializer {

  /**
   * {@inheritdoc}
   */
  public function render() {
    $rows = [];

    if (isset($this-&gt;view-&gt;pager)) {
      $count = $this-&gt;view-&gt;pager-&gt;getTotalItems();
    }
    else {
      $count = 0;
    }

    // If the Data Entity row plugin is used, this will be an array of entities
    // which will pass through Serializer to one of the registered Normalizers,
    // which will transform it to arrays/scalars. If the Data field row plugin
    // is used, $rows will not contain objects and will pass directly to the
    // Encoder.
    foreach ($this-&gt;view-&gt;result as $row_index =&gt; $row) {
      $this-&gt;view-&gt;row_index = $row_index;
      $rows[$row_index] = $this-&gt;view-&gt;rowPlugin-&gt;render($row);
    }

    unset($this-&gt;view-&gt;row_index);

    // Get the content type configured in the display or fallback to the
    // default.
    if ((empty($this-&gt;view-&gt;live_preview))) {
      $content_type = $this-&gt;displayHandler-&gt;getContentType();
    }
    else {
      $content_type = !empty($this-&gt;options['formats']) ? reset($this-&gt;options['formats']) : 'json';
    }

    return $this-&gt;serializer-&gt;serialize(['results' =&gt; ['items' =&gt; $rows, 'totalCount' =&gt; (int) $count]], $content_type, ['views_style_plugin' =&gt; $this]);
  }

}


Then clear cache, and change the plugin for the View under "Style".

So in your case, the final line would look like:

return $this-&gt;serializer-&gt;serialize(['items' =&gt; $rows], $content_type, ['views_style_plugin' =&gt; $this]);