Skip to main documentation content
Reading time · 1 min

Data sources

Adapter architecture, service providers, and API integration. DataSourceFactory is the component that selects the active data source and exposes service implementations to BFF modules.

DataSourceFactory

In apps/bff, the factory injects the active data source and each provider, then exposes a single getServices() API used by BFF modules:

TypeScript
@Injectable()
export class DataSourceFactory {
  constructor(
    @Inject('COMMERCETOOLS_SERVICE_PROVIDER')
    private readonly commercetoolsServiceProvider: CommercetoolsServiceProvider,
    @Inject('MOCK_SERVICE_PROVIDER')
    private readonly mockServiceProvider: MockServiceProvider,
    @Inject(DATA_SOURCE) private readonly dataSource: DataSource
  ) {}

  getServices(): {
    productService: ProductService
    navigationService: NavigationService
  } {
    switch (this.dataSource) {
      case 'commercetools-set':
        return this.commercetoolsServiceProvider.getServices()
      case 'mock-set':
        return this.mockServiceProvider.getServices()
      default:
        throw new Error(`Unknown data source: ${this.dataSource}`)
    }
  }
}

Customisation options

1. Single data source

If you only need one data source:

  • Remove unused providers from DataSourceModule
  • Update the factory to return only that provider’s services
  • Remove the switch and use the provider directly
TypeScript
getServices() {
  return this.commercetoolsServiceProvider.getServices()
}

2. Multiple data sources

The factory can switch between data sources via:

  • Environment variables — Set the DATA_SOURCE environment variable
  • Request headers — Use the x-data-source header for per-request switching (the optional demo/ package can drive this; the storefront does not ship a global picker by default)
  • Runtime configuration — Inject different data sources based on business logic

3. Mixed data sources

You can combine services from different providers:

TypeScript
getServices() {
  const commercetoolsServices = this.commercetoolsServiceProvider.getServices()
  const mockServices = this.mockServiceProvider.getServices()
  const contentfulServices = this.contentfulServiceProvider.getServices()
  return {
    productService: commercetoolsServices.productService,
    navigationService: mockServices.navigationService,
    contentService: contentfulServices.contentService
  }
}

Use this pattern when, for example, products come from Commercetools, navigation from mock during development, and page content from Contentful.

Back to BFF & data · Back to How to work with SHOPin