fontcolor_theme
Deepkit Injector

Erste Schritte

Da Dependency Injection in Deepkit auf Runtime Types basiert, müssen Runtime Types bereits korrekt installiert sein. Siehe Runtime Type.

Wenn dies erfolgreich erledigt ist, kann @deepkit/injector installiert werden oder das Deepkit Framework, das die Library bereits unter der Haube verwendet.

npm install @deepkit/injector

Sobald die Library installiert ist, kann deren API direkt verwendet werden.

Verwendung

Um Dependency Injection zu verwenden, gibt es drei Möglichkeiten.

  • Injector-API (Low Level)
  • Module-API
  • App-API (Deepkit Framework)

Soll @deepkit/injector ohne das Deepkit Framework verwendet werden, werden die ersten beiden Varianten empfohlen.

Injector-API

Die Injector-API wurde bereits in der Einführung zu Dependency Injection vorgestellt. Sie zeichnet sich durch eine sehr einfache Nutzung mittels einer einzigen Class InjectorContext aus, die einen einzelnen DI-Container erstellt und sich besonders für einfachere Anwendungen ohne Module eignet.

import { InjectorContext } from '@deepkit/injector';

const injector = InjectorContext.forProviders([
    UserRepository,
    HttpClient,
]);

const repository = injector.get(UserRepository);

Das Objekt injector ist in diesem Fall der Dependency-Injection-Container. Die Function InjectorContext.forProviders nimmt ein Array von Providern entgegen. Siehe den Abschnitt Dependency Injection Providers, um zu erfahren, welche Werte übergeben werden können.

Module-API

Eine komplexere API ist die Class InjectorModule, mit der Provider in verschiedenen Modulen abgelegt werden können, um pro Module mehrere gekapselte DI-Container zu erstellen. Außerdem ermöglicht dies die Verwendung von Configuration Classes pro Module, wodurch es leichter wird, Konfigurationswerte bereitzustellen, die für die Provider automatisch validiert werden. Module können sich gegenseitig importieren und Provider exportieren, um eine Hierarchie und eine sauber getrennte Architektur aufzubauen.

Diese API sollte verwendet werden, wenn die Anwendung komplexer ist und das Deepkit Framework nicht verwendet wird.

import { InjectorModule, InjectorContext } from '@deepkit/injector';

const lowLevelModule = new InjectorModule([HttpClient])
     .addExport(HttpClient);

const rootModule = new InjectorModule([UserRepository])
     .addImport(lowLevelModule);

const injector = new InjectorContext(rootModule);

Das Objekt injector ist in diesem Fall der Dependency-Injection-Container. Provider können in verschiedene Module aufgeteilt und dann über Modul-Imports an verschiedenen Stellen wieder importiert werden. Dadurch entsteht eine natürliche Hierarchie, die die Hierarchie der Anwendung bzw. Architektur widerspiegelt. Dem InjectorContext sollte immer das oberste Module in der Hierarchie übergeben werden, auch Root-Module oder App-Module genannt. Der InjectorContext hat dann nur eine vermittelnde Rolle: Aufrufe von injector.get() werden schlicht an das Root-Module weitergereicht. Es ist jedoch auch möglich, Provider aus Nicht-Root-Modulen zu erhalten, indem das Module als zweites Argument übergeben wird.

const repository = injector.get(UserRepository);

const httpClient = injector.get(HttpClient, lowLevelModule);

Alle Nicht-Root-Module sind standardmäßig gekapselt, sodass alle Provider in diesem Module nur für sich selbst verfügbar sind. Soll ein Provider anderen Modulen zur Verfügung stehen, muss dieser Provider exportiert werden. Durch das Exportieren wandert der Provider in das Eltern-Module der Hierarchie und kann so verwendet werden.

Um standardmäßig alle Provider an die oberste Ebene, das Root-Module, zu exportieren, kann die Option forRoot verwendet werden. Dadurch können alle Provider von allen anderen Modulen genutzt werden.

const lowLevelModule = new InjectorModule([HttpClient])
     .forRoot(); // exportiert alle Provider ins Root-Module

App-API

Sobald das Deepkit Framework verwendet wird, werden Module mit der @deepkit/app-API definiert. Diese basiert auf der Module-API, sodass deren Möglichkeiten ebenfalls verfügbar sind. Zusätzlich ist es möglich, mit leistungsfähigen Hooks zu arbeiten und Configuration Loader zu definieren, um noch dynamischere Architekturen abzubilden.

Das Kapitel Framework-Module beschreibt dies ausführlicher.

import { App } from '@deepkit/app';
import { FrameworkModule } from '@deepkit/framework';
import { HttpRouterRegistry, HttpBody } from '@deepkit/http';

interface User {
    username: string;
}

class Service {
    users: User[] = [];
}

const app = new App({
    providers: [Service],
    imports: [new FrameworkModule()],
});

const router = app.get(HttpRouterRegistry);

router.post('/users', (body: HttpBody<User>, service: Service) => {
    service.users.push(body);
});

router.get('/users', (service: Service): Users => {
    return service.users;
});
English中文 (Chinese)한국어 (Korean)日本語 (Japanese)Deutsch (German)