16

Using this tutorial Drupal Console's drupal gprr command, I've created a custom REST resource in Drupal 8. I'm able to use this resource to retrieve a simple JSON object that says hello to the current user by doing a GET on:

http://localhost/example/hello?_format=json

The JSON returned then looks like this:

{ "hello": "tyler" }

This is to be expected, as I'm logged in. But when I logout, and do another GET on the resource, the same result is returned:

{ "hello": "tyler" }

Doing a full Drupal cache clear fixes this issue, but I'd like to specifically disable caching on this resource. How can I do that?

As a workaround, I thought adding a time stamp to the query string would work:

http://localhost/example/hello?_format=json&time=123456789

But that also returns the exact same result, no matter what time stamp value is in the query string.

For brevity, here's the skeleton code for building the GET resource:

class ExampleHello extends ResourceBase {

  /**
   * {@inheritdoc}
   */
  public static function create(/* ... */) {
    return new static(/* ... */);
  }

  /**
   * Constructs a Drupal\rest\Plugin\ResourceBase object.
   */
  public function __construct(/* ... */) {
    parent::__construct(/* ... */);
    // ...
  }

  /*
   * Responds to GET requests.
   */
  public function get() {

    $account = \Drupal::currentUser()->getAccount();
    if (!$account->id()) {
      return new ResourceResponse(array(
        'welcome' => 'visitor'
      ));
    }
    return new ResourceResponse(array(
      'hello' => $account->getAccountName()
    ));
  }

}

Is there a configuration/setting I need to set on this plugin to disable caching on GET requests?

4 Answers 4

18

You want to read the Cacheability documentation. it says render arrays, but it also applies to response objects.

ResourceResponse implements CacheableResponseInterface, which has the addCacheableDependency method.

If in any way possible, you want to avoid disabling the cache (which you would do by setting the cache max age to 0), but add the necessary cache contexts and cache tags.

In your cache, that means all you need to do is $response->addCacheableDependency($account).

You also don't need getAccount(), just use currentUser() directly, it's a proxy.

1
  • 3
    You should also avoid using \Drupal in places where you can inject the service, which based on your commented out code, looks like you can do here.
    – mpdonadio
    Dec 8, 2015 at 15:16
17

I had the same issue.

After reading through the documentation and looking through this page, I was able to shut off the cache for my custom endpoint. Here's an example of my working code inside the get() function for my endpoint:

$build = array(
  '#cache' => array(
    'max-age' => 0,
  ),
);

return (new ResourceResponse($myResponse))->addCacheableDependency($build);

Adding this for future reference, hope this helps anyone who needs it.

CacheableResponseTrait documentation page

5
  • 1
    Doesn't work!!!!
    – podarok
    Feb 7, 2018 at 9:24
  • @podarok - this didn't work at first for me either, then after issuing one more drush cr it worked each time afterwards. Apr 18, 2019 at 17:54
  • 1
    worked like a charm. Oct 25, 2019 at 22:58
  • 2
    note that max-age doesn't work for anonymous users and the Drupal core Page Cache module. In this particular case, it will work since the output is the same for ALL anonymous users. If we want a different output for each anonymous user (e.g. time base token), it won't work, see drupal.org/docs/drupal-apis/cache-api/…
    – Peter Wong
    Jul 1, 2020 at 7:14
  • This was the solution. I found that ResourceResponse offers a method setMaxAge() but it does NOT work as I expected. Feb 11, 2022 at 9:18
6

Without any tweaking, you can simply return a ModifiedResourceResponse:

<?php

// ...

use Drupal\rest\ModifiedResourceResponse;

// ...

class ExampleHello extends ResourceBase {

    public function get() {
        // ...
        return new ModifiedResourceResponse($response, 200);
    }

}
1
  • This one is better
    – Baach
    Nov 5, 2021 at 14:27
5

I also had the same issue and the solution for that is:

$response->getCacheableMetadata()->addCacheContexts(['url.query_args', 'url.path']);

You can also see the CacheableMetadata and the cache contexts documentations.

1
  • While the chosen answer is absolutey correct, it requires a long study to understand what the solution is. I have seen this often here on drupal stackexchange, it seems that people favour long and theoretical explanations to to short lines of code straight to the point... Jul 10, 2020 at 15:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.