v5-docs icon indicating copy to clipboard operation
v5-docs copied to clipboard

Documentation about IOC Container

Open paulosandinof opened this issue 3 years ago • 3 comments

Hi. I was trying the other day to use the new version of the framework to achieve something like Spring Boot does in Java with with it's IOC Container, and I noticed that website lacks a little more information about this. I wanted to write something like:

export default interface FooRepositoryInterface {
  findAll(): Promise<Foo>
}
export default class FooRepository implements FooRepositoryInterface{
  findAll(): Promise<Foo> {
    // Implementation
  }
}
export default interface FooServiceInterface {
  list(): Promise<Foo>
}
export default class FooService implements FooServiceInterface {

  constructor(public FooRepositoryInterface repository) {}

  list(): Promise<Foo> {
    return repository.findAll()
  }
}
export default class FooController {

  constructor(public FooServiceInterface service) {}

  index() {
    service.list()
  }
}

It is possible to achieve this kind of behavior with the current version of the framework? If it is, could you guys provide me some examples or guides in how to register the dependencies on the IOC container correctly? I tried to register the classes on the provider but I could achieve the result I wanted. Thanks in advance.

paulosandinof avatar Oct 12 '21 23:10 paulosandinof

Hey @paulosandinof! 👋🏻

It is possible, but not directly like you are doing. You can inject something using the @inject decorator.

import { inject } from '@adonisjs/core/build/standalone'
import YourServiceClass from 'App/Services/YourServiceClass'

@inject()
export default class UsersController {
  constructor(public myService: YourServiceClass) {}

  public async store({ request, auth }: HttpContextContract) {
    console.log(this.myService.name)
  }
}

I am planning to start writing the documentation about IoC soon.

RomainLanz avatar Oct 13 '21 08:10 RomainLanz

Hi @RomainLanz, I was able to kind of reproduce what I wanted with the help of your comment. I'm going to put it here in order to help someone who had this same problem while the documentation gets updated.

Repository Interface

export default interface CityRepository {
    findAll(): string
}

Repository Implementation

export default class CityRepositoryImpl implements CityRepository {
    public findAll() {
        return 'find all'
    }
}

Service Interface

export default interface DashboardService {
    populateDashboard(): Promise<DashboardDTO>
    calculatePricing(): Promise<PricingDTO>
}

Service Implementation

@inject(['Repositories/CityRepository'])
export default class DashboardServiceImpl implements DashboardService {
    constructor(public cityRepository: CityRepository) {}

    public async populateDashboard() {
        return cityRepository.findAll()
    }
}

Controller Class

@inject(['Services/DashboardService'])
export default class DashboardController {
    constructor(public dashboardService: DashboardService) {}

    public async index() {
        return this.dashboardService.populateDashboard()
    }
}

I had to register the dependencies in the AppProvider class, particularly to be able to use dependency injection in classes that already depend of other classes.

export default class AppProvider {
  constructor(protected app: ApplicationContract) {}

  public register() {
    // Register your own bindings
    this.app.container.bind('Repositories/CityRepository', () => new CityRepositoryImpl())
    this.app.container.bind('Repositories/PlanRepository', () => new PlanRepositoryImpl())

    const cityRepository: CityRepository = this.app.container.use('Repositories/CityRepository')
    const planRepository: PlanRepository = this.app.container.use('Repositories/PlanRepository')

    this.app.container.singleton(
      'Services/DashboardService',
      () => new DashboardServiceImpl(cityRepository, planRepository)
    )
  }

  public async boot() {
    // IoC container is ready
  }

  public async ready() {
    // App is ready
  }

  public async shutdown() {
    // Cleanup, since app is going down
  }
}

Thanks for the help. I hope this helps someone else.

paulosandinof avatar Oct 27 '21 14:10 paulosandinof

Can i use documentation from legacy page (4.1)? Or the api is really different?

qrhfz avatar Jul 19 '22 07:07 qrhfz