Drupal 8 REST Endpoint With Entity Reference Field Set To Unlimited Using Views

Drupal 8 REST Endpoint With Entity Reference Field Set To Unlimited Using Views

Using the new Drupal 8 REST api with serialization we were trying to use Drupal 8 views "REST Export" pane on a content type with an entity reference field with the 'unlimited' possible values set. For example a Customer content type, which may have many Contacts.

To make life easier for front-end development, or other websites consuming the data, clients need only call the endpoint once because all the information needed would be in the first response thanks to the use of Entity Reference and it being set to unlimited.

Drupal 8 REST Endpoint Example With Entity Reference Using REST Views

This is an example endpoint configured with a context of customer id past in the url, and what you can achieve:

The objective is to have a simple endpoint like this, and receive a JSON response listing the customer and their contacts, all JSON encoded in one GET request:

GET example.com/api/customer/1

Example Response:

[
   {
      "title":"Fleet Street",
      "field_customer_contacts_export":[
         {
            "email":"finance@example.com",
            "first_name":"Fred",
            "last_":"Willis"
         },
         {
            "email":"jane.austen@example.com",
            "first_name":"Jane",
            "last_":"Austen"
         },
         {
            "email":"press@example.com",
            "first_name":"Johannes",
            "last_":"Gutenberg"
         }
      ]
   }
]

Above we see a JSON response showing the Customer, complete with a JSON array for each Contact attached to this Customer. The Contact entity reference field is set to 'Unlimited', so that add new Contacts are added and removed, the REST Endpoint adapts accordingly.

How to render / serialize entity reference fields with Drupal 8 Rest Export like this?

Out the box the Views REST export works fine if your content type doesn't have entity reference fields. To quote "":

When you create a view with a REST Export display, you will quickly encounter
hard limitations on the data structure, imposed by the Views module's reliance on the Render API:

  • You may want to export a field with multiple values as an array.
    By default, this is only possible by exporting the raw field, as the rendering
    process also concatenates the output into a single string.
  • An entity reference can only be exported as a fully rendered string,
    and not as a nested structure with multiple individual fields.
  • Boolean and numeric fields can only be exported as strings, rather than
    the appropriate JSON primitives.

The Views and Field plugins in the Rest Views module add all of these features.

We needed to show all fields of the referenced entity, and an expose these n referenced entities as a JSON array.

Essentially we needed Drupal 8 to serialize the rendered entity, but Drupal Views core cannot serialize a rendered entity in this way. What we wanted was to answer the question: 'how to do Drupal views group by entity reference?' and out a JSON rest endpoint.

If this was a web view, we'd simply use rendered entity, with a custom display mode. However, just choosing 'rendered entity' in a REST endpoint doesn't work as Burschka points out. To achieve a REST Export of entity reference fields in views, Drupal's REST export by default doesn't serialize the entity reference; it only pulls in the entity reference title.

Thankfully, after much trial and error we found REST Views written by Christoph Burschka (cburschka). Rest Views allows us to create a JSON formatted endpoint including the serialization of all entity references and their fields. This works even when the entity reference field has unlimited values permitted. REST views can be configured to merge unlimited field values into a JSON array.

There's also a project 'rest-export nested' but we haven't experimented with this.

Eilyin's post on 'Rest API through views drupal 8 how to modify serializer' provides good backgroupd to creating your own serializer. Burschka's REST Views module goes all the way providing a very intuitive solution.

How to use REST Views Module

Here's an example of how to use the REST Views module. The scenario is:

Imagine you're building a CRM and your Customers have many Contacts for example:

  • Joe from Marketing
  • Clare from Sales
  • Sally the Director

These people are all stored in a Contact types and attached to a Customer content type via an Entity reference field set to 'unlimited'.

You want to create a REST endpoint which when called, spits back your Customer entity, and all associated Contacts in one request.

1. Create a Contact content type

Create a basic Contact content type. For example first name/last name and an email address. This will be the references entity for when a Customer has many contacts.

e.g:

Showing fields of a Contact content type in Drupal 8

(You may want to use an actual user account if this if your exact use-case)

2. Create a customer content type

Create a Customer content type, and add a field of type Entity Reference named Customer Contacts:

Adding Customer Contacts entity reference field to Customer content type in Drupal 8

Set the allowed number of values to unlimited:
Drupal setting allowed number of values to Unlimited

Set reference type to Contact

3. Create a new REST Export View called 'Customer'

Create a new view, but choose "REST EXPORT", and check 'Provide a REST export.

We've set the endpoint path to api/customer/% because we want the client to supply a customer id when making the request.

Creating Customer REST endpoint in Drupal 8

We could, for example, go further and create another endpoint called /customers which listed all customers or paginated the result showing all possible customer Ids.

4. Choose Show Fields on REST Export

By default the view will output the entire entity, we want to select show 'fields'.

Choose Show fields on the REST export

On all fields, click them and unckeck "Link to the Content" because this will clean up the REST endpoint output. Do this for every field you add. You don't need a link to the content without your JSON response, if you do, add an id field instead and create another endpoint for that content type.

Uncheck Link to the conten to clean up REST output

We now have clean JSON output, showing just the title field of the Customer content type. Next we need to add our Contacts unlimited entity reference field to the view.
JSON Output from the REST Cutomer endpoint

5. Add Serializable Entity Reference Field (Unlimited values) To View

Click 'add fields' to your view and search for the 'Customer Contacts (serializable) field to your view. Notice the serializable appended to the field name. This has been made available to you thanks to the REST Views module (make sure it's installed).

Adding Unlimited valued Entity Reference field to a Drupal 8 REST View

Press 'Add and configure fields', then choose the correct formatter (next step).

6. Choose 'Export Rendered Entity' Formatter

The REST Views module makes available the 'Export rendered entity' formatter. Choose this, and leave the default 'Multiple Field Settings' as they are.

Setting Drupal views field formatter to Export rendered extity

Press apply and you now have a fully serialized JSON enpoint for getting customers and their associated contacts via the entity reference!

To finish off, add a contextual filter to your view to filter on Customer id because at the moment the view will send back all customers and their associates contacts.

7. Add contextual filter (Optional)

The objective is to be able to pass a customer id to example.com/api/customer/<customer-id> and have the endpoint only send back data related to that customer. Do this by adding contextual filter:

Set your view path to allow a customer ID to be passed to endpoint

We set it to api/customer/%:
Add a wildcard filter to allow Customer id to be passed to endpoint

Add contextual filter based on Customer id

Add Contextual filter to view

Search and select "ID" based on the ID of Customer:

Set a contextual filter on Customer ID

ID Means the node id of the Customer content type. So if our customer has an ID of 15, our REST call would be example.com/api/customer/15.

Add some basic filter validation (optional)

Here we've set: If a customer ID is not given, then we show Access Denied. Also we validate the customer ID to be numeric:

Restricting REST endpoint contextual filter wih validation

Finally, remember to enable authentication on your endpoints. Drupal's REST web services API does respect node access settings, but it's easy to mistakenly give access to resources. Be careful. For example, look into using Drupal's built-in Basic Auth (and use over SSL).

Completed Restful Enpoint using Rest Views

Using a tool like Advanced Rest Client developers can easily play with the endpoint and inspect the response visually:

Using Advanced Rest Client to test Drupal RESTful endpoint with entity reference

Useful Drupal 8 resources regarding REST View with serialization

Collect recurring payments with Subscribie - Try Now