Insight

How to Retrieve an Image Using Decoupled JSON:API

A man in a white button up shirt stands smiling in front of a metal wall
Philip Curley Senior Product Developer

Overview

One of the first challenges when decoupling Drupal 8 with the JSON:API module is grabbing your images and files with your API query. Assuming you want to render a image field this tutorial walk through how to format your HTTP request in order to retrieve the image path.

Assuming you make a call for a list of Node pages like so:

http://drupal.localhost/jsonapi/node/page

This request returns a JSON body response. Examine the data you'll notice that your image field, in this case "field_header_image" isn't listed in the Node attributes with your other fields. Instead it's located in the relationships object and it contains some meta information...but not the path! So why does JSON:API put some data in attributes and some data in relationships? and how do we obtain that field data with a single fetch?

"data": {
  "attributes":  { },
  "relationships": {
    "field_header_image": {
      "data": {
        "type": "file--file",
        "id": "6cae425b-4e15-4e35-8af4-9090c97ceccb",
        "meta": {
          "alt": "A field with many yellow flowers",
          "title": "",
          "width": 1920,
          "height": 1080
        }
      }
    }
  }
}

 

If we dive into the JSON:API specification we'll discover how Drupal's data gets exposed through the schema as resource objects. In particular let's look at a small section in the Resource Objects definition about what the document may contain:

attributes: an attributes object representing some of the resource’s data.
relationships: a relationships object describing relationships between the resource and other JSON:API resources.

And here is our answer: Nodes which are represented as Resource Objects are related to Media and File entities which are also Resource Objects. Therefore the referenced Image entity is not an attribute of the Node but a relationship of it.

So how can we format our request to include the Media entity? JSON:API specifies an `includes` parameter and so we'll create a URL like this for our JSON:API call:

http://drupal.localhost/jsonapi/node/page?include=field_header_image

 

"included": [
  {
    "type": "file--file",
    "id": "6cae425b-4e15-4e35-8af4-9090c97ceccb",
    "links": { },
    "attributes": {
      "drupal_internal__fid": 25,
      "langcode": "en",
      "filename": "yellow-flowers.jpg",
      "uri": {
        "value": "public://2019-10/yellow-flowers.jpg",
        "url": "/sites/default/files/2019-10/yellow-flowers.jpg"
      },
      "filemime": "image/jpeg",
      "filesize": 623488,
      "status": true,
      "created": "2019-10-10T17:00:34+00:00",
      "changed": "2019-10-10T17:00:52+00:00"
    },
    "relationships": { }
  }
]

And there we go! Now we've returned our Node data and image field data in a single fetch and response.