How do I correctly setup caching for my custom API routing? I have custom module with some routes which return JSON, for instance terms of a vocabulary.

routing.yml

mymodule.terms:
  path: '/api/terms/{vid}'
  defaults:
    _controller: '\Drupal\mymodule\Controller\MyModuleController::getTerms'
    _title: 'Terms'
  requirements:
    _permission: 'access content'
    vid: '^(foobar|barfoo)$'


Controller:

public function getTerms($vid) {
  $response = $this-&gt;jsonifyVocabulary($vid);
  return $response;
}

private function jsonifyVocabulary($vid) {
  $request = \Drupal::request();
  $lang = $request-&gt;query-&gt;get('lang', 'en');
  $output = [];
  $taxonomyManager = \Drupal::entityManager()-&gt;getStorage('taxonomy_term');
  $terms = $taxonomyManager-&gt;loadTree($vid, 0, 1, false);
  $response = CacheableJsonResponse::create($output);

  debug(1);

  foreach ($terms as $term) {
    $term = Term::load($term-&gt;tid);
    if ($term-&gt;hasTranslation($lang) &amp;&amp; $lang !== $term-&gt;language()) {
      $term = $term-&gt;getTranslation($lang);
    }
    $entry = [
      'tid' =&gt; (int) $term-&gt;id(),
      'label' =&gt; $term-&gt;getName(),
    ];

    // $response-&gt;addCacheableDependency($term);
    $output[$vid][] = $entry;
  }

  $response-&gt;setData($output);

  $cacheMeta = (new CacheableMetadata())-&gt;addCacheContexts(['url.query_args:lang']);
  $response-&gt;addCacheableDependency($cacheMeta);

  return $response;
}


Thanks to this answer I know how to actually add the URL params as a cache context, but the

debug(1);


always gets called, I guess I just somehow have to tell Drupal that this JSON response's cache should relate to that route...

I don't use the core's REST module on purpose since I find it hard to configure to output exactly what I need.
This is all you need to set up caching for a response:

  $response = CacheableJsonResponse::create($output);
  return $response;


If you use a response that implements the CacheableResponseInterface it will be cached indefinitely.

Cache tags

When you add a list of taxonomy terms you have to add these tags:

  $list_tags = $this-&gt;entityTypeManager()-&gt;getDefinition('taxonomy_term')-&gt;getListCacheTags();
  $cache_metadata-&gt;addCacheTags($list_tags);

  foreach ($terms as $term) {
    $cache_metadata-&gt;addCacheableDependency($term);
  }


This will invalidated the cache entry when the terms are modified in the database.

Cache contexts

When you use a query parameter add this context:

  $lang = $request-&gt;query-&gt;get('lang', 'en');
  $cache_metadata-&gt;addCacheContexts(['url.query_args:lang']);


This will vary the cache by the query arguments.

Cacheable metadata in a response

To put all this together create at the beginning of the controller an empty CacheableMetadata object:

  $cache_metadata = new CacheableMetadata();


While building the content collect the cache metadata for all dependencies you use as described in the two examples before and then add the metadata to the response at the end of the controller:

$response-&gt;addCacheableDependency($cache_metadata);