Skip to content

Adding Dependencies

This guide shows you how to inject services and repos into your use-cases.

Overview

Devux uses dependency injection (Inversify) to wire up your components. You don't instantiate classes manually - you declare what you need using inject decorators and the framework provides it.

Adding a Repo to a Use-Case

Steps

  1. Run pnpm devux
  2. Select "Endpoints"
  3. Select "Manage dependencies"
  4. Choose the endpoint
  5. Select "Add dependency"
  6. Choose the repo to inject

Result

The CLI adds the inject decorator and property to your use-case:

typescript
import { injectGetCustomerByEmailRepo } from '@/__internals__/domains/customers/repos/get-customer-by-email/get-customer-by-email.repo.inversify.tokens';

@fullInjectable()
export class CreateCustomerUseCase extends TransactionalUseCase<CreateCustomerRequest> {

    @injectGetCustomerByEmailRepo() private readonly getCustomerByEmailRepo!: IGetCustomerByEmailRepo;

    protected override async _execute(input: CreateCustomerRequest): Promise<void> {
        // Now you can use this.getCustomerByEmailRepo.execute(...)
    }
}

Adding a Service to a Use-Case

Steps

  1. Run pnpm devux
  2. Select "Endpoints"
  3. Select "Manage dependencies"
  4. Choose the endpoint
  5. Select "Add dependency"
  6. Choose the service to inject (domain service or app service)

Result

typescript
import { injectEmailService } from '@/__internals__/app-services/email-service/email-service.inversify.tokens';

@fullInjectable()
export class CreateCustomerUseCase extends TransactionalUseCase<CreateCustomerRequest> {

    @injectEmailService() private readonly emailService!: IEmailService;

    protected override async _execute(input: CreateCustomerRequest): Promise<void> {
        // Now you can use this.emailService
    }
}

Multiple Dependencies

You can inject as many dependencies as needed:

typescript
@fullInjectable()
export class CreateOrderUseCase extends TransactionalUseCase<CreateOrderRequest> {

    @injectCreateOrderRepo() private readonly createOrderRepo!: ICreateOrderRepo;
    @injectCalculatePricingService() private readonly pricingService!: ICalculatePricingService;
    @injectEmailService() private readonly emailService!: IEmailService;

    protected override async _execute(input: CreateOrderRequest): Promise<void> {
        const pricing = await this.pricingService.execute({ items: input.items });
        const order = await this.createOrderRepo.execute({ ...input, total: pricing.data.total });
        await this.emailService.sendOrderConfirmation(input.email, order.data);
    }
}

Type Safety

All dependencies are type-safe:

  • Inject functions are typed to their interface
  • Import statements are added automatically
  • The tester class is regenerated with the new dependency