Muzammil Naseer
Muzammil Naseer

Reputation: 1141

Multi environment Express Api

I am working on an Multi-Environment API based on Express framework. What i want is to keep my configuration dynamic, e.g. This Api would be able to serve both mobile apps and Web apps. If request is coming from mobile source than config-app-1.json should be included, otherwise config-app-2.json.

Currently I have config-app-1.json, config-app-2.json, config-db-1.json, config-db-2.json and a configManager.js class which sets required configuration in app.listen(). In other application modules i require configManager and use the necessary configurations. This however leads to code duplication issue in individual functions. Each function has to get reference of db and application settings in its local scope.

I would like to know what are best practices for a multi-environment API build using Express framework.

Upvotes: 5

Views: 466

Answers (3)

Bamieh
Bamieh

Reputation: 10906

These are configuration files, here is my approach.

File Structure

.
├──  app.js
├── _configs
|   ├── configManager.js
|   ├── database.js
|   └── platform
|       ├── mobile.js
|       └── desktop.js

Environment Configs

Configration files are js modules for each device, then the configManager handles which one is active based on device.

//mobile.js example
module.exports = {
    device: 'mobile',
    configVar: 3000,
    urls: {
        base: 'DEVICE_SPECIFIC_BASE_URL',
        api: 'DEVICE_SPECIFIC_BASE_URL'
    },
    mixpanelKey: 'DEVICE_SPECIFIC_BASE_URL',
    apiKey: "DEVICE_SPECIFIC_BASE_URL",
}

Database Config

Database configurations should be centralized.

Usually you can connect to multiple databases within the same node instance, however it is not recommended. if you absolutely have to, just use two objects (instead of "mongodb" replace with "mobileMongoDb" and "desktopMongoDb") but i recommend that you use one database and divide it into two main documents, or use certain prefixes set in your platform-specific configs.

// databse.js example
module.exports= {
  mongodb: {
  host      : 'localhost',
  port      : 27017,
  user      : '',
  password  : '',
  database  : 'DB_NAME'
  },
}

configManager.js (Putting things together)

This is a simple file for demonstration only..

var userAgent = req.headers['User-Agent'];
var isMobile = /Mobile|Android|/i.test(userAgent);



// require them all to be cached when you run node.
var configs = {
   mobile: require('./platform/mobile' ),
   desktop: require('./platform/desktop' )
}
var activeConfig = isMobile? configs.mobile : configs.desktop;
var dbConfigs = require('./databse');


var mongoose = require('mongoose');
var express = require('express');
var app = express();

app.get('/', function (req, res) {
   var finalresp = 'Hello from ';
   finalresp += isMobile? 'mobile' : 'desktop;
   finalresp += activeConfig.configVar;
   res.send(finalresp);
});

mongoose.connect(dbConfigs.mongodb.host, function(err) {  
   if(isMobile) { /* ... */ }
});

Detect Mobile from header

read more here https://gist.github.com/dalethedeveloper/1503252

Upvotes: 1

Lars de Bruijn
Lars de Bruijn

Reputation: 1518

Can the source of the request (e.g. Mobile - Web) change during runtime? In other words can request 1 come from a mobile device and request 2 from the web?

If so, you could look at the user agent in the headers to determine the kind of device you're dealing with. This does make you dependent on the user agent though, and if it's not sent you won't have a way of identifying your client.

req.headers['User-Agent'];

If you own the clients yourself, you can add a property to every request, say an extra header. req.headers['X-Client-Type'] = 'Mobile'; //Web.

This way you aren't dependent on the user agent and still able to identify the type of each client.

Lastly, if you are dealing with third party clients, other people making applications to hit your API you might want to make them register their application. (Name, developer name, contact information, maybe agree to some type of service agreement, and also state the type of client, Web vs Mobile).

You'd then be able to fetch the type of each client on every new request.

Upvotes: 1

XCEPTION
XCEPTION

Reputation: 1753

You can set environment variables. What I usually do is have multiple config files as you have mentioned.

Then set environment variable NODE_ENV in local, development and production as "LOCAL", "DEVELOPMENT" and "PRODUCTION" respectively.

Then you can refer the environment by following code

ENV = process.env.NODE_ENV
if(ENV === 'PRODUCTION') {
    mainConf = JSON.parse(fs.readFileSync(path.join(__dirname, '/config/main-production.json')))
    dbConf = JSON.parse(fs.readFileSync(path.join(__dirname, '/config/db-production.json')))

} else if(ENV === 'DEVELOPMENT') {
    mainConf = JSON.parse(fs.readFileSync(path.join(__dirname, '/config/main-development.json')))
    dbConf = JSON.parse(fs.readFileSync(path.join(__dirname, '/config/db-development.json')))
} else if(ENV === 'LOCAL') {
    mainConf = JSON.parse(fs.readFileSync(path.join(__dirname, '/config/main-local.json')))
    dbConf = JSON.parse(fs.readFileSync(path.join(__dirname, '/config/db-local.json')))
}

Make sure you set environment variables properly on environment of each server. Use the config json retrieved from the above code the way you want.

Upvotes: 1

Related Questions