SHOPin Logo
Skip to main documentation content

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