Cached JSON responses in Drupal 8

This week I was working on a Drupal 8 project that includes a page that uses Drupal as a simple proxy to convert a weak XML API into a simple JSON response. To ensure good performance I wanted to ensure I had cached JSON responses.

When I first built the site I hadn’t yet gotten my head around Drupal 8 caching, and so the JSON responses weren’t cached and therefore the page was slow. After some issues with the site caused me to have to look at this part of the project again I decided it was time to try to do something about this.

Drupal 8’s use of Symfony means we have great tools for simple tasks like providing JSON responses. Originally in the controller all I had to do was provide the JsonResponse class an array of data and it would handle the rest:

That’s all well and good if you don’t want your response to ever be cached, but Drupal provides a CacheableJsonResponse class that links up to the rest of the Drupal 8 caching engine to provide much better performance than a stand Symfony JsonResponse. But it turns out the docs kinda suck for explaining how to use it. After a great deal of digging I found this Question on StackExchange which gave me what I needed.

Edit: You must enable the Internal Dynamic Page Cache module to get CacheableJsonResponse to work correctly. Thank you for the correction.

9 thoughts on “Cached JSON responses in Drupal 8”

  1. Hi,
    With this method, the Cache-Control HTTP header is force to “no cache, must revalidate”.
    Even if you try to force the header from the controller, using :
    $response->headers->set(‘Cache-Control’, ‘max-age=60 public’);

    With CacheableJsonResponse, at some point the response is override by another header…

    Everything works fine with JsonResponse, but you cannot benefit from render cache…

    1. Huh I’m not sure. I just rechecked the site I built with the code in the gist, and the cache control header comes back correctly (“max-age=180, public” the time limit was changed since that was written). That said, I also checked a site I just finished building that also does that same thing and it gives the same response you see. I’ll have to investigate the differences in other aspects of their setup.

    2. Thanks for asking about this because it got me to go take another look and notice I’d forgotten to set a maximum age for the page cache. Drupal 8’s cache control header is controlled by the performance setting for Page cache maximum age (on:
      /admin/config/development/performance). You might also be interesting in checking out: and

  2. I know it’s a bit old post, but for anyone looking for answers I would say it’s worth noting that Internal Dynamic Page Cache module needs to be enabled for that to work. And it is not enabled by default :). I have just spent half a day on debugging this issue.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.