How do I construct a thin controller with a dependent service? For the first time I am trying to architect a reasonably complex Drupal 8 module, and not sure of best practice for the controller. 


I need to route paths to a controller.
I intend the controller to be
thin (very little logic, doesn't need to testable)
Heavy lifting will be via service class/es configured and defined by the module.


Extending ControllerBase should be the right path for a thin controller, however when I look in Core at the moment I notice a number of controllers that both extend ControllerBase and implement ContainerInjectionInterface. I would only implement ContainerInjectionInterface to be able to inject a different container for testing, not just selection of service in the create method, but Core is still in flux and I am not sure exactly why they are doing this.

I feel that I should extend ControllerBase, add a __construct that fetches the container and pulls in the non-standard service/s that I require via $this->container()->get() and indeed that does work. I also don't need the create method required to implement ContainerInjectionInterface.

Am I correct? I know I will need to go through a few iterations of getting the services right but want to get THIS bit right from the start and understand why I am doing it.

Thanks in advance.
ContainerInjectionInterface is used as a part of a static factory method pattern.

This way, a class's constructor can specify all of the services it needs, and its factory method, in this case create(), can satisfy the constructor by retrieving services from the container.

The instantiated controller should never have its own copy of the container, if at all avoidable.

A brief example:

&lt;?php

namespace Drupal\book\Controller;

use Drupal\book\BookManager;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class BookController extends ControllerBase implements ContainerInjectionInterface {
  protected $bookManager;

  public function __construct(BookManager $bookManager) {
    $this-&gt;bookManager = $bookManager;
  }

  public static function create(ContainerInterface $container) {
    return new static(
      $container-&gt;get('book.manager')
    );
  }

  public function bookRender() {
    $book_list = array();
    foreach ($this-&gt;bookManager-&gt;getAllBooks() as $book) {
      $book_list[] = l($book['title'], $book['href'], $book['options']);
    }
    return array(
      '#theme' =&gt; 'item_list',
      '#items' =&gt; $book_list,
    );
  }
}


This would be declared as a controller in a routing file like this:

_content: \Drupal\book\Controller\BookController::bookRender