• Skip to main content
  • Skip to footer

InRhythm

Your partners in accelerated digital transformation

  • Who We Are
  • Our Work
  • Practices & Products
  • Learning & Growth
  • Culture & Careers
  • Blog
  • Contact Us

Node.js

Dec 21 2020

Lightning Talk: Creating a Proxy with Node + Express

tldr;

I created a Node and Express proxy that rams together two websites / apps. If you are ever asked to develop code for a site you don’t have access to, this could save the day.

  1. Download the code:
    https://github.com/mattbillard/code-collider-v2
  2. Watch the video:

My most recent hobby project involved building a Node and Express proxy to ram two websites or apps together. I dubbed it “The Code Collider.” 

The idea of the Code Collider was born about two years ago when I was given a rather difficult coding challenge at a client. Another department had a website and we were being asked to iframe it. As you might know, iframes have a lot of “interesting nuances” as they might politely be called, one of which is that if a user right-clicks on a link and chooses “Open in new tab,” they will break out of the parent’s iframe and go directly to the iframed child site. Of all things, I was asked to write some code to prevent this and provide my solution to the other team. There was just one catch: I had no way of running the other team’s site in my local environment and thus (or so I initially thought) no easy way to test my code as I wrote it. 

This situation comes up more often than you’d think. There are several reasons a developer might not be able to run a site or app in their local environment. Perhaps it’s complex to set up, involves a lot of permissions, or the other team just can’t be bothered to spare the time to help you out. Regardless of the reason, I did eventually strike upon a novel way to solve the problem.

After what felt like a meandering odyssey of Stack Overflow posts, I managed to cobble together a Node and Express project that took the other team’s site, piped it through a proxy, injected my script into it, and served it to my browser. Even though my innovation worked and I was able to deliver the final code requested, there was just one thing that bothered me: I always had the nagging feeling that I had only gotten the proxy to work through a mixture of stubborn persistence and blind luck. I resolved to rebuild it from scratch in my free time one day, piece by piece, actually understanding how the solution worked – and that as it turns out is exactly what I did.

The Architecture

Here’s a diagram of how it works:

The browser makes a request to our Node Express proxy server where we then have three scenarios:

  1. If the user requested an HTML page, we need to combine the page from website 1 and 2. The proxy first asks website 1 and then website 2 for its HTML. It then modifies the two HTML files, combines them, and returns the result to the browser. (Details on how this works below.)
  2. The HTML page will then request the CSS, JavaScript, and other assets it requires. These requests will again go through the proxy which will pass on the requests. If website 1 has the asset, great, the proxy will return it to the browser. 
  3. If website 1 does not have the asset, the proxy will then ask website 2 and return it to the browser.

Here are screenshots of the result:

In this example, we’ll use the real InRhythm.com website as the target into which we’ll inject some local code (in this case a basic Create React App project). The final result on the right is an actual screenshot of the 2 websites living together in the same browser window. Now this is pretty exciting; the target website and the code that you are developing could be anything!

How it Works

  1. As mentioned above, website 1 and 2’s HTML are combined. This involves a few steps. Webpages can’t have 2 doctype, html, head, or body tags, so we’ll use some regex to strip those. Now that website 2’s HTML is ready, we’ll inject it before website 1’s closing </body> tag. 
  1. And here is the code that shows our modifications to website 1’s HTML. It shows a few things.

    Firstly, many websites have full ‘absolute URLs’ for their links. They look like this: https://www.inrhythm.com/who-we-are/
    The problem is if the user clicks on this, they’ll be taken away from our proxy and go to the target website. We’ll solve this by removing all www.something.com bit and keep just the bit after the slash.

    Secondly, we show injecting the CSS discussed above to remove backgrounds and allow clicks to pass through website 2 to website 1. (Keep in mind this will probably be slightly different depending on the two sites you are combining.)

    Thirdly, we show injecting the HTML from website 2 we modified from above before the closing </body> tag.

Gotchas to Avoid

As mentioned above, it took a lot of research as well as trial and error to solve all the technical hurdles this project presented. Here are some of the main ones below.

  1. Websites usually compress or “Gzip” their content. Normally this is a great thing. It means less data is transferred and websites load more quickly. This is not going to work for our case however. You can’t parse, manipulate, and modify HTML if it looks like gibberish. The solution was actually quite simple: as it turns out, there’s a header you can send with your request to ask the server not to Gzip anything.
  1. There’s another header we need to send however. Because we’re using a proxy, all requests are going to have the header ‘host’ set to ‘localhost’. Now this is probably not a problem for most sites, but to the target server, this doesn’t look like a very normal request, and indeed, I did find some websites responded oddly and returned pages that looked nothing like I expected. The solution again was quite simple, just modify one of the headers of our request. 
  1. Now as you’ve probably gathered from above, we’ve modified our requests quite a lot, and as a result this is going to cause the browser to do some odd things. The solution to this problem is to delete the ‘content-length’ header before the proxy sends your browser any response. This will stop the browser from truncating the response and removing all the hard work we did. 
  1. Finally, I’ll mention one other problem I solved. If you are combining sites that use https, the proxy might complain that the SSL certificates don’t match what it’s expecting. Turns out it’s rather easy to relax this with the following code: 

Conclusion

That’s it. Feel free to download the code, follow the instructions in the readme, and open your browser to localhost:8000 . You should be able to see two web sites rammed together. 

Written by Matt Billard · Categorized: Cloud Engineering, InRhythmU, Learning and Development, Web Engineering · Tagged: express, Node.js, proxy

Apr 25 2017

Engineering Driven Culture – InRhythm’s Code Lounge

 

[huge_it_slider id=”3″]

Last week, driven by the feedback from our engineering leadership team, we held InRhythm U’s first-ever Code Lounge, inviting everyone from across the company and a few external guests to learn new skills, brush up on existing ones, or just get help on a personal project.

Code Lounge featured technical “stations” for Angular, React, React Native, Express, Vue, Node.js, Java, QA, UX and Product, each led by an InRhythm senior developer instructor. Accompanied by food and drinks on the company, the event provided an easy atmosphere and low-key way for everyone to network and learn a thing or two!

Here are a few key takeaways and learnings from Code Lounge:

  1. To understand what is important to our engineers, we need to be constantly listening to and engaging with our teams. While Vue and Java were not on our list of station offerings originally, in putting the event together we quickly found out that they are in high demand. Luckily, we were able to add both of these to our agenda, thanks to our very talented engineers who were able to lead these discussions.
  2. Collaboration happens when culture is driven from bottom up, not top down. Our engineers and UX/product leads single-handedly drove Code Lounge, with management simply enabling from the background with budget and logistics support. The magic of the night was the true collaboration seen across the stations, individuals coming prepared with best practices in their domains to share without being asked, and amazing learning and teaching happening in tandem across the room.
  3. Angular seemed to be the least popular station at the event, perhaps because a large part of our team is already fluent in Angular or perhaps due to newer technologies featured, such as Vue and React – these were the most popular and buzzed-about tables.
  4. We love learning and development at InRhythm, but admittedly beer on tap, Lombardi’s pizza, pool and music make it even better.

At InRhythm, our goal is to give our people the best opportunities for learning and growth. This goal is something I feel very passionate about as do all our senior leaders across the organization. Code Lounge is just one example of how we keep our company culture and ourselves at the top of our game!  If you want to find out more, visit us at www.inrhythm.com.

 

Written by Shivani York · Categorized: Bootcamp, Code Lounge, Events, Financial Services, InRhythm News, Learning and Development, Software Engineering, Talent · Tagged: Angular, Code lounge, engineers, Java, JavaScript, Learn, Node, Node.js, React, React native, software engineering

Nov 03 2015

CTO Video Roundup – Empire Node NYC

Last Friday, myself and 5 of my team at InRhythm went to the Empire Node NYC conference in NYC. We learned of the history and future of Node/io.js, the upcoming and existing features of the platform and much more.

Links:

  1. Node LTS and release plans – https://nodesource.com/blog/essential-steps-long-term-support-for-nodejs
  2. Slides for ES6 module talk –  http://benjamn.github.io/empirenode-2015/#/1
  3. The Evolution of Modularity – http://slides.com/linclark/modularity/#/
  4. Using Docker with Node – https://docs.docker.com/examples/nodejs_web_app/

Written by John K. Paul

Written by inrhythmAdmin · Categorized: Software Engineering · Tagged: cto updates, Node.js, video

Aug 10 2015

Nothing is Impossible – Making the Switch from ES5 to ES6

I have been writing javascript for about a decade now. When I first saw ES6, it felt like JavaScript had been empowered with so many new functionalities, I just had to rewrite everything to ES6. Once I actually begun that process it was tricky in the existing code base and not possible to rewrite everything using pure ES6 functionalities. I took a step back and decided to start with a smaller subset of ES6 features – class, let/const, lexical scoping, and object. Here’s what I learned along the way:

I have been writing javascript for about a decade now. When I first saw ES6, it felt like JavaScript had been empowered with so many new functionalities, I just had to rewrite everything to ES6. Once I actually begun that process it was tricky in the existing code base and not possible to rewrite everything using pure ES6 functionalities. I took a step back and decided to start with a smaller subset of ES6 features – class, let/const, lexical scoping, and object. Here’s what I learned along the way:

Before getting started you need to prepare the development environment with tools to help write code is ES6, I used gulp (Grunt is also a good choice) to build files. Here’s some Gulp plugins you can install to get started with compiling ES6 to ES5 compatibility versions.

  • ESLint (gulp-eslint) – An open source project which helps validate your ES6 javascript files and also lets you configure rules in .eslintrc in order to target ES6 features as per your needs.
    • File: https://github.com/jskungfu/linters/blob/master/.eslintrc
    • Plugin: https://www.npmjs.com/package/gulp-eslint/
  • Babel transpiler (gulp-babel) – There many browsers which do not support ES6 so we need to transforms ES6 code back down to ES5.
    • Plugin: https://www.npmjs.com/package/gulp-babel
  • Gulp-concat – To concatenate javascript files into one file.

Here is a simple gulp file to help get started:

    
    var gulp = require('gulp');
    var babel = require('gulp-babel');
    var concat = require('gulp-concat');
    var eslint = require('gulp-eslint');
    //Register compilation task
    gulp.task('compile', function() {
        // place code for your default task here
        return gulp.src([
            'src/libs/file1.js',
            'src/libs/file2.js',
            'src/xxx.js',
            'src/yyyy.js'
        ])
        // eslint() attaches the lint output to the eslint property
        // of the file object so it can be used by other modules.
        .pipe(eslint({
            "useEslintrc": true
        }))
        //eslint.format() outputs the lint results to the console.
        // Alternatively use eslint.formatEach() (seeDocs).
        .pipe(eslint.format())
        .pipe(babel({
            "sourceMaps": false
        }))
        .pipe(concat('yourfilename-concat.js'))
        .pipe(gulp.dest('dist'));
    });
    //Register default task
    gulp.task('default', ['compile']);
    

Here are some of the things I learned during my rewriting process:

1. Class

Class was really easy to get started, constructor methods really stands out and it offers a much nicer, clearer syntax for creating objects and dealing with inheritance.

Here is a simple class example:

    
    class Meter {
        constructor(config) {
            this.count = config.count;
        }
        getCount() {
            return this.count;
        }
        static reload() {
            window.location.reload();
        }
    }
    

Interesting things for developers from ES5 world to note:

  1. We don’t have to write the function key word when starting new function
  2. No comma needed for adding a new function
  3. We can’t stick default properties to a class like we do with prototypical inheritance, you have to use this.xyz = ‘abc’ from the function to add a property to the instance.
  4. Static functions are not tied to an instance and you can not call it calling this.reload() instead you have to use a constructor to use this method Meter.reload().
  5. Class declarations are not hoisted

It takes some time to forget the practices that we have been following for years, but once you get hold of it, you will never want to go back again.

2. Variable declaration

Let and const are two new ways to declare variables and both of them are block scope.

2.1 Let

Let is similar to var but it is available to the current code block.

    
    function get() {
        if (condition) {
            let value = "xyz";
            return value;
        } else {
            //value does not exist here
            return null;
        }
    }
    

2.2 Const

    
    if (condition) {
        const MAX_COUNT = 10;
        //more code which uses variable
    }
    //MAX_COUNT is not accessible here
    

In the code above MAX_COUNT is declared within the if statement and MAX_COUNT is only available within the block. As soon as the block statement is finished executing MAX_COUNT is destroyed.

Some important facts to notice here:

  1. We must provide a value when we declare constant.
  2. If we try to assign a value to MAX_COUNT again, the line will throw error.

Interesting things for developers from ES5 world to note:

  1. Let and const are not hoisted to functions or block scope – they are not even hoisted within their own block scope.
  2. We must provide a value to the const variable and if you try to reassign a value to a const variable then it will throw an error.

3. Arrow function

This is one of my favorite feature of ES6, functions defined with a new syntax that uses an arrow(=>) and it works as below:

  • Lexical this binding – The value of this inside of the function is determined by where the arrow function is defined not where it is going to be used.
  • Can not be used with new keyword – it does not provide a new keyword
  • Scope remains constant – this value can not be changed inside the function, it maintains the same value throughout the life cycle of the function.
  • An arguments object is not available – you must pass named arguments.

Examples:

    
    var getName = () => "Hetal";
    // will be transpiled to
    var getName = function () {
        return "Hetal";
    };
    

Lexical this binding

This is the most common use case where we had to come up with storing scope in ES5 world and it has been made easy in ES6 with arrow function.

ES5 you would probably write some function like as below:

    
    var Badge = {
        userName: "Hetal",
        getBadge: function () {
            return "<div class='badge'>" + this. userName + "</div>";
        },
        init: function (type) {
            var self = this;
            //notice how difficult it is maintain scope here
            $(document).on("click", function () {
                self.getBadge.call(self, e);
            });
        }
    };
    

ES6 will make same code easier to write

    
    var Badge = {
        userName: "Hetal",
        getBadge: function () {
            return "<div class=‘badge’>" + this. userName + "</div>";
        },
        init: function (type) {
            //using lexical scope,
            //we can write same code in one line as below
            $(document).on(“click”, (e) => { this.getBadge(e)});
        }
    };
    

This is great way to reduce code lines and write clean code.

 

File Size comparison:

The transpiling process adds some extra code to make it compatible with all browsers which increases the size of the final output file. For instance the file (minified and concatenated versions) that I rewrote is 25KB in ES5 javascript but the ES6 version comes out to be 32KB.

To conclude, Initially I thought that it would be really difficult to convert my project into ES6 but once I started taking baby steps by picking some ES6 features, configuring workflow process using gulp, it all eventually fell in place. I really enjoyed rewriting my ES5 javascript project files into ES6 – which also helped me better organize and structure my codebase and opened my mind to a whole new world. I hope what I learned will help someone who has just started converting projects into ES6. Happy coding!

References:
https://leanpub.com/understandinges6/read

Written by Hetal Thakkar

Written by inrhythmAdmin · Categorized: Software Engineering · Tagged: code, ES6, Node.js, tutorial

Aug 04 2015

A Sneak Peek of InRhythm’s NYC Meetup on Node.js

On July 15th the crowd gathered at IRHQ for a Meetup on Node.js. Our senior NY consultant guided everyone through an exercise using Node and then we transitioned to hands-on coding. During the workshop we built an SMS-driven customer service tool using PM2, Gulp, React, WebSockets, ES6 Map, LevelDB, Deploying to Heroku, BrowserSync, Twilio(SMS), and more. We gained a good sense of how to build realtime apps with Node.js, set up a live/responsive build process, and deploy to virtual servers for prototyping. There was a lot of discussion surrounding how Node can be applied to solve business problems. The night was a success and we are excited for many more Meetups to come! Take a look!

Written by inrhythmAdmin · Categorized: Events, Software Engineering · Tagged: education, Meetup, Node.js, React, sms, tools

  • Go to page 1
  • Go to page 2
  • Go to Next Page »

Footer

Interested in learning more?
Connect with Us
InRhythm

140 Broadway
Suite 2270
New York, NY 10005

1 800 683 7813
get@inrhythm.com

Copyright © 2022 · InRhythm on Genesis Framework · WordPress · Log in

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPT
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Non-necessary
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
SAVE & ACCEPT