VelaVela
Fundamentals

Providers

Providers are injectable services that encapsulate business logic.

Providers are classes decorated with @Injectable() that can be injected into controllers and other providers through dependency injection. They are the primary way to encapsulate business logic and keep controllers thin.

Creating a Provider

The @Injectable() decorator marks a class as available for dependency injection:

import { Injectable } from '@velajs/vela';

@Injectable()
class SpiritsService {
  private spirits = [{ name: 'Calcifer' }];

  findAll() {
    return this.spirits;
  }

  create(spirit: { name: string }) {
    this.spirits.push(spirit);
    return spirit;
  }
}

Registering Providers

Providers must be registered in a module's providers array to be available for injection:

import { Module } from '@velajs/vela';

@Module({
  providers: [SpiritsService],
  controllers: [SpiritsController],
})
class SpiritsModule {}

Constructor Injection

Vela resolves dependencies automatically based on constructor parameter types:

@Controller('spirits')
class SpiritsController {
  constructor(private readonly spiritsService: SpiritsService) {}

  @Get()
  findAll() {
    return this.spiritsService.findAll();
  }

  @Post()
  create(@Body() body: { name: string }) {
    return this.spiritsService.create(body);
  }
}

Custom Providers

For more control over how providers are created, use custom provider syntax:

Value Providers

Supply a static value:

@Module({
  providers: [
    { provide: 'API_URL', useValue: 'https://api.example.com' },
  ],
})
class AppModule {}

Factory Providers

Use a factory function with optional dependencies:

@Module({
  providers: [
    {
      provide: 'DATABASE',
      useFactory: (config: ConfigService) => {
        return new Database(config.get('DB_URL'));
      },
      inject: [ConfigService],
    },
  ],
})
class AppModule {}

Alias Providers

Point one token to another:

@Module({
  providers: [
    SpiritsService,
    { provide: 'ELEMENTAL_SERVICE', useExisting: SpiritsService },
  ],
})
class AppModule {}

Injection Tokens

For non-class tokens, use InjectionToken to create a typed token:

import { InjectionToken } from '@velajs/vela';

const CONFIG = new InjectionToken<AppConfig>('app-config');

Use it with custom providers:

@Module({
  providers: [
    { provide: CONFIG, useValue: { debug: true, port: 3000 } },
  ],
})
class AppModule {}

Inject it using the @Inject() decorator:

@Injectable()
class AppService {
  constructor(@Inject(CONFIG) private config: AppConfig) {}
}

Provider Scopes

Control the lifecycle of provider instances with the scope option:

ScopeBehavior
Scope.SINGLETONSingle shared instance (default)
Scope.TRANSIENTNew instance every time it is resolved
Scope.REQUESTNew instance per incoming request
@Injectable({ scope: Scope.TRANSIENT })
class TransientService {
  constructor() {
    // created fresh each time it's injected
  }
}

@Injectable({ scope: Scope.REQUEST })
class RequestScopedService {
  // unique instance per request lifecycle
}

Request-scoped providers use a child container created for each incoming request. Singleton providers are inherited from the parent container.

Edit on GitHub

Last updated on

On this page