Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Including related model data in Page API request

I've got a relatively simple setup running using SilverStripe 3.2.1 with the restfulserver addon and using a variety of widgets which are associated to a Page using the elemental addon.

When I make a GET request via the API to retrieve some of Page #1's data, I can see the associated ElementAreaID:

# GET /api/v1/Page/1.json?fields=Title,URLSegment,Content,ElementArea 
{
  "Title": "Welcome",
  "URLSegment": "home",
  "Content": "A bunch of HTML here from all the widgets in the page...",
  "ElementArea": {
    "className": "ElementalArea",
    "href": "http://ss.local:3000/api/v1/ElementalArea/11.json",
    "id": "11"
  }
}

If I follow the links through the ElementalArea API calls it will list out all of the elements in my page:

# GET /api/v1/ElementalArea/11.json
{
  "ID": "11",
  "Widgets": [
    {
      "className": "Widget",
      "href": "http://ss.local:3000/api/v1/Widget/9.json",
      "id": 9
    },
    {
      "className": "Widget",
      "href": "http://ss.local:3000/api/v1/Widget/8.json",
      "id": 8
    },
    ...
  ]
}

And if I follow those API paths it will serve up the contents of the latest version of each of the Widgets.

My question is how can I include certain fields from the Widget DataObjects within the original Page field list?

I'd like ideally to have the Content field from each Widget be returned in an array with the initial Page API request.


For reference:

  • A Page has one ElementArea
  • An ElementArea has many Widgets
  • A Widget contains content that I want for my Page
like image 490
scrowler Avatar asked Feb 25 '16 22:02

scrowler


1 Answers

Preamble: It doesn't seem there's currently a way to output array-like datastructures with the RESTful server module (except for relations of course). The proposed solution is a hack that abuses how JSONDataFormatter formats output.

Since JSONDataFormatter uses forTemplate to render a field before converting it to JSON, we can create our own Object renderer that returns an array instead of a string via forTemplate. This might look like this:

class FlatJSONDataList extends ViewableData
{
    protected $list;

    public function __construct(array $list)
    {
        parent::__construct();
        $this->list = $list;
    }

    public function forTemplate()
    {
        return $this->list;
    }
}

Then in your Page, it should be sufficient to have an additional method, like so:

public function getWidgetContents()
{
    return FlatJSONDataList::create(
        $this->ElementArea()->Widgets()->column('Content')
    );
}

Then you can include WidgetContents in your Field-list to get all widget Content fields in an array:

GET /api/v1/Page/1.json?fields=Title,URLSegment,Content,WidgetContents 
like image 114
bummzack Avatar answered Oct 14 '22 07:10

bummzack