2
votes

Can someone please suggest how I can set this up. Here is the scenerio.

I am developing an angular app with an Azure Mobile Services back end.

In angular I have resources that point to the Mobile Service API path. I have a config factory that returns the base service path. I want the dev/staging slot to point to the -dev api and the production slot to point to the production API path.

I can create two config factories, but I'm not sure how to tell it to use the dev one in the staging slot and the production one in the production slot. For a .net app with server code I would use the config stuff, or maybe environmental variables, but this is all client side code.

I thought to just have two web sites, once deployed from a dev branch and one deployed from the master and have a different config... but once I merge dev to master then the config change merges too.

I'm not sure if it matters, but I am deploying from Visual Studio Online as part of the build.

How can I accomplish this?

4

4 Answers

1
votes

If you can key off the client hostname of the production versus the development servers ( or not the production server), then you can inject an $http interceptor to rewrite request URLs. In my app.js, I have something like:

var DEV_SRVR = 'http://my-machine.example.com:8000';
var PRODUCTION_FRONT_END_CLIENT_SUFFIX = 'DEPLOYMENT';
app.factory('REST_Interceptor',[

  function() {
    var request = function(config) {
      if (RegExp(PRODUCTION_FRONT_END_CLIENT_SUFFIX,'i').test(window.location.host)) {
        return config;
      }
      var rest_request_regex = new RegExp('^.*?/rest/(.*)$');
      config.url = config.url.replace(rest_request_regex, DEV_SRVR+'/$1');

      return config;
    }

    return {
      request: request
    }
  }])

app.config([
          '$httpProvider',
  function($httpProvider) {
    $httpProvider.interceptors.push('REST_Interceptor');
}])

Thus, requests from AngularJS like:

$http.get('/rest/foo/')

Go to http://my-machine.example.com:8000/foo/ if the client is not the production client interface, otherwise it goes to /rest/foo/ of the production host.

2
votes

I was able to solve this very same problem. I have development, testing and production environments and they each need to connect to different API end points. I was able to accomplish this using a grunt plugin called grunt-ng-constant

Basically once you install the plugin, modify your Gruntfile and inside the grunt.initConfig add something like this:

ngconstant: {
  // Options for all targets
  options: {
    space: '  ',
    wrap: '"use strict";\n\n {%= __ngModule %}',
    name: 'config',
  },
  // Environment targets
  development: {
    options: {
      dest: '<%= yeoman.app %>/scripts/config.js'
    },
    constants: {
      ENV: {
        name: 'development',
        apiEndpoint: 'http://your-development.api.endpoint:3000'
      }
    }
  },
  production: {
    options: {
      dest: '<%= yeoman.dist %>/scripts/config.js'
    },
    constants: {
      ENV: {
        name: 'production',
        apiEndpoint: 'http://api.livesite.com'
      }
    }
  }
},

Register the Grunt task like so:

grunt.registerTask('serve', function (target) {
  if (target === 'dist') {
  return grunt.task.run(['build', 'connect:dist:keepalive']);
}

grunt.task.run([
  'clean:server',
  'ngconstant:development', // ADD THIS
  'bower-install',
  'concurrent:server',
  'autoprefixer',
  'connect:livereload',
  'watch'
]);

});

Now every time you run grunt serve it will generate a config.js file that holds your development constants. You can configure different tasks such as grunt testing or grunt production to generate the testing or production constants instead.

Finally you add the config.js to your index.html like so:

<script src="/scripts/config.js" />

And register the config module in your app:

var app = angular.module('myApp', [ 'config' ]);

In your controller you can get your "environment" variables like this:

angular.module('myApp')
  .controller('MainCtrl', function ($scope, $http, ENV) { // ENV is injected

     $scope.login = function() {

     $http.post(
        ENV.apiEndPoint, // Our environmental var :)
        $scope.yourData
     ).success(function() {
        console.log('Cows');
     });

   };

 });

With this approach you can easily automate the entire deployment pipeline. You can have a CI server push your changes to the appropriate servers and build the correct version of your app.

Here's a very helpful resource for you to read and from which I took the code samples: http://mindthecode.com/how-to-use-environment-variables-in-your-angular-application

Hope this helps you!

0
votes

You might be interested in looking how David Ebbo and I setup this scenario. In David's talk at Build he discusses how to configure two websites to communication with each other. The source code for his talk is available on GitHub called ToDoApp. If you prefer to read over watch, there was also an article written about David's talk which is available in the Azure Documentation called Deploy a Complex Application predictably in Azure

-1
votes

You can set App Settings for you site and slot from the Azure Portal, and set separate settings for the dev and production slots.

See these docs for more details: https://azure.microsoft.com/en-us/documentation/articles/web-sites-staged-publishing/#configuration-for-deployment-slots