Saturday, February 28, 2015

Define Proxies in GRUNT to get rid of CORS

I had a start to my angularjs project with the awesome GRUNT+YEOMAN+NPM combo and it was a great going so far and I was enjoying everything till I had to introduce HTTP server calls to fetch data from my backend server :). But when I started integrating the apis, I got CORS errors in my browser console (Cross origin requests not allowed) :(.

Googling the cause I got to know that somehow I would need to proxy my server calls via grunt server so as to get the response. I started and got the fix after these steps. Once I was okay with the setup, I thought of sharing my experience :).

In order to configure the Gruntfile.js so as to enable the Server to proxy your BACKEND SERVER calls follow the below steps:

#1. Get grunt-connect-proxy installed in  your project using the below command, it will tell the NPM(Node Package Manager) to install the "grunt-connect-proxy" as a developer dependency.

    npm install grunt-connect-proxy --save-dev


#2. Now as per the documentation at grunt-connect-proxy you can enable it via adding the below line at somewhere on top of your grunt file (say after the line: module.exports = function (grunt) { // the first line of your grunt file)

   grunt.loadNpmTasks('grunt-connect-proxy');

#3. Now goto the "connect config" and add the proxy configuration as below just before the "livereload" configuration so as to proxy your backend urls

   connect: {
       options: {
         port: 9000,
// This is your grunt server port.
         hostname: 'localhost',
// Your machine as host
         livereload: 35729 // Port for livereload to connect
       },
       proxies: [{
         context: '/api', //
the api pattern you need to proxy(i am going to proxy all the requests that are having a path as /api)
         host: 'localhost', // the backend server host ip
         port: 8080 // the backend server port
       }],
       livereload: { 

        //livereload configuration here.
       }
   }

#4. Update the middleware configuration in livereload with the below one so as to enable proxies. Note you might be having the middleware configuration written like returning a object definition (eg. return[...]). So backup that and follow the step #5 so as to add your configuration to the middleware configuration updated in this step, otherwise things might not work like in my case, styles and bower dependencies were not getting resolved.

   
   connect: {
       options: {
         port: 9000,
// This is your grunt server port.
         hostname: 'localhost',
// Your machine as host
         livereload: 35729 // Port for livereload to connect
       },
       proxies: [{
         context: '/api', //
the api pattern you need to proxy(i am going to proxy    all the requests that are having a path as /api)
         host: 'localhost', // the backend server host ip
         port: 8080 // the backend server port
       }],
       livereload: { 

            options: {
             open: true,
             base: [
             '.tmp',
             '<%= yeoman.app %>'
             ],
        middleware: function (connect, options) {
          var middlewares = [];
           
          if (!Array.isArray(options.base)) {
            options.base = [options.base];
          }
           
         // Setup the proxy
         middlewares.push(require('grunt-connect-proxy/lib/utils').proxyRequest);

         // Serve static files
         options.base.forEach(function(base) {
           middlewares.push(connect.static(base));
         });
              
         return middlewares;
       }
     }

       }
   } 


#5. In my case i was having my middleware configuration as returning an object definition like below:

     middleware: function (connect) {
            return [
              connect.static('.tmp'),
              connect().use(
                '/bower_components',
                connect.static('./bower_components')
              ),
              connect().use(
                '/app/styles',
                connect.static('./app/styles')
              ),
              connect.static(appConfig.app)
            ];
          }


In order to make this configurations to be there in my new middleware configuration, I inserted the below lines in my new middleware configuration. I am simply pushing my configurations into the "middlewares" array created in step #4 so as to make my things work.

         middlewares.push(connect.static('.tmp'));
        middlewares.push(connect().use(
                '/bower_components',
                connect.static('./bower_components')
              ));
        middlewares.push(connect().use(
                '/app/styles',
                connect.static('./app/styles')
              ));
        middlewares.push(connect.static(appConfig.app));


I inserted these lines just before the "return middlewares;" statement in step #4.


#6. And finally just add the 'configureProxies:server' statement just before the "'autoprefixer:server'," statement like below in the 'SERVE' task


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

    grunt.task.run([
      'clean:server',
      'wiredep',
      'concurrent:server',
      'configureProxies:server',
      'autoprefixer:server',
      'connect:livereload',
      'watch'
    ]);



#7. You are all set :). Just do- 'grunt serve' and see the magic.

and yes to have a cross check if all izz well just have a look at your console that your server should say:

Running "configureProxies:server" (configureProxies) task
Proxy created for: /api to localhost:8080
 



Thanks,
Happy Coding!