How do I correctly setup caching for my custom API routing?
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);