For image files, it would be nice to have the image styles URLs available to client applications. These URLs can't be simply calculated on the client-side due to the anti-DoS tokens added to the end of the URLs.

Proposed resolution

For file entities that have image styles, list their URLs in the response. Exactly what is the best way to implement this is debatable. Adding them as extra "links" might make the most sense, perhaps labelled by their image style. It would probably be a good idea to prefix the image style name to reduce the likelihood of naming collisions (in case someone makes an image style with the name "self", for example):

{
  "data": [
    {
      "type": "file--file",
      "id": "aeb7262d-5d1c-4252-a7f7-7c32e7f9c20c",
      "attributes": { ... },
      "links": {
        "self": "http://drupal.dd:8080/jsonapi/file/file/aeb7262d-5d1c-4252-a7f7-7c32e7f9c20c",
        "image_thumbnail": "http://drupal.dd:8080/sites/default/files/styles/thumbnail/image.gif?itok=AbCdEfGh",
...
        "image_large": "http://drupal.dd:8080/sites/default/files/styles/large/image.gif?itok=aBcDeFgH"
      }

Alternately, I could see using "meta" members to pass the URLs. Perhaps something like:

{
  "data": [
    {
      "type": "file--file",
      "id": "aeb7262d-5d1c-4252-a7f7-7c32e7f9c20c",
      "attributes": { ... },
      "meta": {
        "image_styles": {
          "thumbnail": "http://drupal.dd:8080/sites/default/files/styles/thumbnail/image.gif?itok=AbCdEfGh",
...
          "large": "http://drupal.dd:8080/sites/default/files/styles/large/image.gif?itok=aBcDeFgH"
        }
      }

Comments

hampercm created an issue. See original summary.

e0ipso’s picture

Status: Active » Postponed (maintainer needs more info)

I like this idea, but I don't like it at the same time.

I go in a loop over these:

PRO: It is very useful for consumers, and that's what an API is for. It's not for winning a cleanliness gold medal.
CON: In certain setups it can increase the payload size significantly.
PRO: The payload size will matter less with gzip compression.
CON: Using image styles defined in the server breaks the no presentation in the back-end rule and that is bad for many, many reasons.

Thoughts?

e0ipso’s picture

I think this feature may be a good candidate for the separate contrib being planned in #2846488: Explore abstracting away "Drupalisms".

hampercm’s picture

I can see this as being a part of an "extras" module, as some people won't need this, and as @e0ipso mentioned, it can increase payload size significantly.

As for image styles being presentation on the back-end, this feels like a gray area to me, though in the end this may just be arguing semantics. Many frontend projects focus on optimizing image sizes and delivery to the client; this is often done manually by pre-processing the images, and giving the filenames appropriate suffixes or putting them in different directories. Drupal just happens to have this functionality available out-of-the-box. In the end, image styles greatly reduces the total data transfer, as images are frequently the largest portion of data transferred for a website/application.

Either way, this feels like a very important feature to have somewhere. It even come up as a question during a presentation I've given regarding JSON API.

justinlevi’s picture

Is there a way currently to get to the image style urls with JSON API? I'm having a hard time wrapping my brain around the request syntax for a simple request to a media reference entity on a basic page content type.

Spleshka’s picture

We ran into the same issue and I feel that this issue will become a hot topic soon :) Developers certainly should be able to fetch images including their image styles. As mentioned in #4, there is no way to generate image style url from the frontend due to the tokenization of this url, and this is the key of the issue.

My proposed solution would be to let frontend to include list of required image styles into the json api request. Something like this (very, very rough and dirty example!):

{
  'include': 'fileFieldName.image_style',
  'fields[file--file]': 'url,200x200,500x700'
}

I'm not yet (!) familiar with json api source code so can't judge if this direction if sufficient or not, so maintainers' opinion is needed && appreciated.

Yet another question here is if maintainers would like to see this 'image_style' feature in the json_api module OR if it should go to the new module json_api_extras (json_api submodule or standalone)?

I'm willing to help in getting this feature done, as we urgently need it. So fast responses here might save the world!

Spleshka’s picture

Status: Postponed (maintainer needs more info) » Active
Spleshka’s picture

There's probably another solution which is outside of Json API scope. Things like Sharp ,Image Resizer or Imaginary might be better from architectual point of view:
1. Frontend becomes independant of Drupal's image styles
2. Images aren't linked to the backend (file storage can be moved to S3 or similar, no links to the backend, etc)

However, it brings additional complexity like configuration + support of image resizing software (and most likely standalone server as well, because it's not supported by most of the hosting providers).

So even though enterprise level solutions have a way around this issue, simple projects still need "a simple solution to get a resized image".

Wim Leers’s picture

We're working on this in core too: #2825812: ImageItem should have an "derivatives" computed property, to expose all image style URLs. Over there, we're considering adding a image_style_urls property to the ImageItem field type.

That'd then make it automatically available. For core REST, for JSON API, for GraphQL … and for auto-generated documentation such as https://www.drupal.org/project/openapi or https://www.drupal.org/project/docson.

dannyjohnson1’s picture

Subscribe...

e0ipso’s picture

Project: JSON:API » JSON:API Extras

Moving to the JSON API Extras project.

e0ipso’s picture

Version: 8.x-1.x-dev » 8.x-3.x-dev

This deserves some attention. Moving to the latest module version.

Gold’s picture

I have just hit this issue myself.

Looking at the "no presentation in the back-end" and the payload size concerns, could it be possible to just deliver the anti-DoS token with the current payload? The image style URLs are easily derived from the source image URI and the frontend devs would be working in tandem with the backend devs.

This we end up with something like this;

{
  "type": "file--file",
  "links": {...},
  "attributes": {
    "drupal_internal__fid": 5,
    "langcode": "en",
    "filename": "example.jpg",
    "uri": {
      "value": "public://media/image/example.jpg",
      "url": "/sites/default/files/media/image/example.jpg"
    },
    "itok": "AbCdEfGh"
    ...
  },
  "relationships": {...}
},

Given this would only be adding one extra attribute it could also be moved back to the JSON:API module.

Thoughts?

Gold’s picture

Ah... Never mind. Just saw that buildUrl() would be creating a unique token for each derivative. Not sure how useful the suggestion at #13 is now.