JSON API: Getting Just the Data You Need with Sparse Fieldsets

The JSON API module provides a standard method for requesting entities from a Drupal site via HTTP requests. When you make a request to JSON API, the data is returned as either a single entity object or an array of entity objects. In JSON API terms each of these entities is called a resource.

Each resource contains everything Drupal knows about it – the created date, changed date, revision ID, a relationship to the author, and much more. This data comes in the form of resource attributes and relationships. While all this data is critical for Drupal’s inner workings, our own application is most likely only interested in a fraction of what’s returned. All this unnecessary data can lead to larger HTTP responses coming across the network and more data getting stored in memory than we need.

Fortunately the JSON API spec outlines a method for specifying exactly what attributes and relationships you want the server to return. This is referred to as Sparse Fieldsets.

Defining sparse fieldsets on your requests is easy. You just need to add the appropriate query parameter to the url of your API’s endpoint. Here is the general format:

...?fields[resource-type]=field_name1, field_name2

Here’s an example of a request to a basic Contenta installation for recipes for which we only want titles and categories:

/api/recipes?fields[recipes]=title,category

Here’s a Gist of the responses – with sparse fieldsets and without. The former is 700+ lines of JSON. The latter is over 3200. In practical terms, assuming these responses were gzipped, it’s the difference between 2.5KB and 22.7KB. In this case the data we care about is actually only 10% of the full payload.

You may be wondering why the query parameter key is in the form of fields[recipes] instead of simply fields. Can’t we just assume we’re talking about recipes based on the path? No. We can’t assume we’re talking about recipes.

In our example, we also want to know what category the recipes belong to. The category field is a relationship. In Drupal speak, it’s a term reference field to a Category taxonomy. A Category is actually it’s own resource. As seen in our previous response, the relationship on a recipe to a category is shown as a Resource Identifier Object – a simple object with type and ID properties. If we want to know more about a category than it’s UUID, we could make a separate request for something like:

/api/categories/91f073ef-f9de-4bb6-b1b1-afef9654fb9d

Well that seems tedious and would require a bunch of additional requests. Fortunately, the JSON API spec also outlines a method of including related resources as a means of reducing the amount of subsequent requests needed. The result is what is called a Compound Document – a document with related resources included along with our primary resources.

To include categories along with our recipes, we simply use the include query parameter. Like so:

/api/recipes?include=category

The response is a compound document with the full representation of categories referenced by our recipes.

This brings us back to why we can’t assume we are only talking about recipes when defining our sparse fieldset query parameters. A response can include more than just the primary resource.

Sparse fieldsets also work on included resources. As noted above, our compound document includes the full representation of the category. We’re going to pretend we really only care about the category names.

Here is our final url which limits recipes to title and category, includes categories and limits those to their name:

/api/recipes?include=category&fields[recipes]=title,category&fields[categories]=name

Here is our final json response.

Sparse fieldsets are great for keeping your JSON API responses trimmed down and limiting your responses to just the data you need.

If you’re interested in learning more about making API requests to Contenta with JSON API, come see my talk, Building Confidence in APIs with Postman, at Drupalcon Nashville on March 10th, 2018. I hope to see you there!

Code Drupal 8 JavaScript

Read This Next