Loopback-next: Environment Specific Configuration for Datasources

Created on 20 Feb 2019  路  3Comments  路  Source: strongloop/loopback-next

Feature proposal

Hi, this is more a proposition to simplify of what's already working as a quick fix in LB4. With loopback 3 we could select the db configuration with the file name :

example :

dbName.production.js // for NODE_ENV=PRODUCTION
dbName.js // for NODE_ENV ignoring (local development)

This could be interesting to do something similar with loopback 4 later. Anyway it's more to propose something if someone is looking for a quick fix solution for now.

Current Behavior

Here is the quick-fix : the goal is to detect if the NODE_ENV equals 'PRODUCTION' (or whatever) and override the db configuration thanks to the DbDataSource constructor :

   const dataSourceConfigProd = {
      name: 'db',    
      connector: 'postgresql',
      url: process.env.DATABASE_URL
    }
    const dbDataSource = new DbDataSource(dataSourceConfigProd);
    this.bind('datasources.db').to(dbDataSource);

dataSourceConfigProd is your db production configuration, can work with anything (connector mysql, mongodb, etc... , host, port, password, etc...). (make sure to install the good connector)

in application.ts

import {BootMixin} from '@loopback/boot';
import {ApplicationConfig} from '@loopback/core';
import {RepositoryMixin} from '@loopback/repository';
import {RestApplication} from '@loopback/rest';
import {ServiceMixin} from '@loopback/service-proxy';

import {DbDataSource} from './datasources/db.datasource'; // import DbDataSource

export class Application extends BootMixin(
  ServiceMixin(RepositoryMixin(RestApplication)),
) {
  constructor(options: ApplicationConfig = {}) {
    super(options);

// HERE IS START OF THE BLOCK TO ADD

  if(process.env.NODE_ENV === 'PRODUCTION') {
    const dbDataSource = new DbDataSource({
      name: 'db',    
      connector: 'postgresql',
      url: process.env.DATABASE_URL
    });
    this.bind('datasources.db').to(dbDataSource);
  }

// HERE IS END OF THE BLOCK TO ADD

    // Set up the custom sequence
    this.sequence(MySequence);

    this.projectRoot = __dirname;
    // Customize @loopback/boot Booter Conventions here
    this.bootOptions = {
      controllers: {
        // Customize ControllerBooter Conventions here
        dirs: ['controllers'],
        extensions: ['.controller.js'],
        nested: true,
      }
    };
  }
}

So, this works for now

Expected Behavior

Later, just change the json names with db.json and db.production.json for example, like in LB3

Regards.

feature feature parity

Most helpful comment

I put back my working solution :

// src/datasources/db.datasource.ts

import {inject} from '@loopback/core';
import {juggler} from '@loopback/repository';
import * as devConfig from './app.datasource.json'; // import dev json
import * as prodConfig from './app.ds.production.json'; // import prod json

export class DataSourceSettings{
  name: string
  connector: string
  url?: string
  file?: string
};

let config: DataSourceSettings;

if( process.env.NODE_ENV === 'PRODUCTION') {
  console.log(' --- Database in Prod Mode --- ')
  config = prodConfig;
  config.url = process.env.DATABASE_URL; // can add properties from environment var at start.
  console.log(config);
} else {
  console.log(' --- Database in Dev Mode --- ')
  config = devConfig;
  console.log(config);
}

export class AppDataSource extends juggler.DataSource {
  static dataSourceName = 'db';

  constructor(
    @inject('ds.config.db', {optional: true}) dsConfig: object = config,
  ) {
    // console.log(dsConfig);
    super(dsConfig);
  }
}

dev datasource JSON

{
    "name": "db",
    "connector": "memory",
    "file": "./data/db.json"
  }

prod datasource JSON

{
    "name": "db",    
    "connector": "postgresql",
    "url": ""
}

All 3 comments

I put back my working solution :

// src/datasources/db.datasource.ts

import {inject} from '@loopback/core';
import {juggler} from '@loopback/repository';
import * as devConfig from './app.datasource.json'; // import dev json
import * as prodConfig from './app.ds.production.json'; // import prod json

export class DataSourceSettings{
  name: string
  connector: string
  url?: string
  file?: string
};

let config: DataSourceSettings;

if( process.env.NODE_ENV === 'PRODUCTION') {
  console.log(' --- Database in Prod Mode --- ')
  config = prodConfig;
  config.url = process.env.DATABASE_URL; // can add properties from environment var at start.
  console.log(config);
} else {
  console.log(' --- Database in Dev Mode --- ')
  config = devConfig;
  console.log(config);
}

export class AppDataSource extends juggler.DataSource {
  static dataSourceName = 'db';

  constructor(
    @inject('ds.config.db', {optional: true}) dsConfig: object = config,
  ) {
    // console.log(dsConfig);
    super(dsConfig);
  }
}

dev datasource JSON

{
    "name": "db",
    "connector": "memory",
    "file": "./data/db.json"
  }

prod datasource JSON

{
    "name": "db",    
    "connector": "postgresql",
    "url": ""
}

I would like to propose a different solution, see https://github.com/strongloop/loopback-next/issues/2556

@bajtos I'm ok with your solution. This issue can be closed

Was this page helpful?
0 / 5 - 0 ratings