Running Angular applications inside a Docker container – part 1

Introduction

This is the first post in a series of posts in which I will deploy an Angular2 application and an Express server inside a Docker container. By the end of the series, I will build a sample application (client and server) and use Nginx with HAProxy to proxy the requests to their intended servers and also dynamically balance the requests when we add or remove servers from the cluster.

What is Docker?

Docker is an open-source software that enables you to automate the deployment of any application into software containers. Containers, unlinke virtual machines, share the operating system on which they are running. This means that containers are much more efficient in using system resources resulting in more instances of your application running on the same hardware.

Prerequisites

  1. Install Docker with brew install docker if you are on a Mac or use your OS intaller from https://www.docker.com/community-edition#/download.
  2. Make sure you have NPM installed on your system.
  3. Install AngularCLI by running npm install -g @angular/cli.

Creating the Angular application.

We will use the Angular CLI to generate a sample Angular app:

  • Create a new directory for your project: mkdir ng-2-docker
  • Generate a new angular app. I will name it client: cd ng-2-docker ng new client
  • Start the development server by running ng serve
  • Open your browser and navigate to http://localhost:4200

If you see the message “app works!” you are good to go.

“Dockerizing” the client application.

We begin by creating a Dockerfile inside the client application folder. This file is like a blueprint for the docker container. We will create a new image from the base nodejs 7 image, copy all the application source files into our image, install de dependencies and then run the application.

ng-2-docker/client/Dockerfile

#  Create a new image from the base nodejs 7 image.
FROM node:7
# Create the target directory in the imahge
RUN mkdir -p /usr/src/app
# Set the created directory as the working directory
WORKDIR /usr/src/app
# Copy the package.json inside the working directory
COPY package.json /usr/src/app
# Install required dependencies
RUN npm install
# Copy the client application source files. You can use .dockerignore to exlcude files. Works just as .gitignore does.
COPY . /usr/src/app
# Open port 4200. This is the port that our development server uses
EXPOSE 4200
# Start the application. This is the same as running ng serve.
CMD ["npm", "start"]

Before building our image we just need to change one thing. By default, the webpack-dev-server is not accessible from other hosts. In order to make it available we need to add a parameter into our package.json file.

ng-2-docker/client/package.json

From this:

...
"scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
...

Into this:

...
"scripts": {
    "ng": "ng",
    "start": "ng serve -H 0.0.0.0",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
...

Now we need to build our image. Make sure you are in the client directory and then run:

docker build -t ng-2-docker/client .

This will build our custom nodejs image that will run our Angular client application.
In order to test our image we need to deploy it in a container: docker run --rm -p 80:4200 ng-2-docker/client

  • –rm parameter will immediately remove the container when it stops.
  • -p parameter maps the container’s 4200 port to port 80 on your local machine.
  • The last part of the command it’s the image that we’ve just built.

We can test our application by opening http://localhost in your browser.
If you see the message “app works!” then you are successfully running your Angular application inside d docker container. You can also run docker ps and you should see one running container.

Putting it all together with Docker Compose

Mapping container’s port to local machine’s port it’s ok for what we need but in a real production environment you would most probably use Nginx to reverse proxy the requests to your application server/s. When a request comes on port 80 in your Nginx server, it will be forwarded to port 4200 into your application server (webpack-dev-server in our example). In order to be able to easily orchestrate multiple images and containers we are going to use docker-compose. This utility comes pre-installed with Docker.

First, we are going to create our Nginx image. We will start from a base Nginx image and just add our own default configuration to proxy the requests to our application server.

  • Create new folder named nginx in the root folder of our project: mkdir nginx
  • Into this new folder create 2 files: Dockerfile and default.conf

ng-2-docker/nginx/default.conf

server {
    location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://client:4200/;
    }
}

The config above will instruct Nginx (which will run in a separate container) to proxy all request coming on / to the angular client application running in another container on port 4200.

Now for the Dockerfile:

ng-2-docker/nginx/Dockerfile

#  Create a new image from the base nginx image.
FROM nginx
# Overwrite nginx's default configuration file with our own.
COPY default.conf /etc/nginx/conf.d/

Now, int root of the project create a new file called docker-compose.yml

ng-2-docker/docker-compose.yml

version: '2'

services:

  # Build the container using the client Dockerfile
  client:
      build: ./client

  # Build the container using the nginx Dockerfile
  nginx:
    build: ./nginx
    # Map Nginx port 80 to the local machine's port 80
    ports:
      - "80:80"
    # Link the client container so that Nginx will have access to it
    links:
      - client

Now in the root folder run docker-compose up -d --build --remove-orphans and everything should magically work. Test it at http://localhost.

Useful docker-compose commands:

  • docker-compose ps list running containers
  • docker-compose stop stops our comntainers
  • docker-compose start starts our containers
  • docker-compose up -d --build --remove-orphans re-builds the containers. Useful if you modify any configuration or source file
  • docker-compose logs brings up the container logs

Editing code without container re-build?

This is all fine and dandy but it’s a bit of a headache to re-build the containers everytime you modify a css file. In order to map the client container’s code We just need to add a line of code into our docker-compose.yml file.

ng-2-docker/docker-compose.yml

...
  # Build the container using the client Dockerfile
  client:
      build: ./client
  # This line maps the contents of the client folder into the container.
      volumes:
        - ./client:/usr/src/app
...

In order to test our changes run:

  • docker-compose up -d --build --remove-orphans to re-build the image
  • Open your browser at http://localhost. You should see app works!
  • Edit ng-2-docker/client/src/app/app.component.ts and change the title value to “app works with Docker!”
  • Refresh your browser and see the magic happening.

What’s next?

In the next post we will create an API server with Express and MongoDB and connect our client application to it.

P.S: The code is available here

Catching global errors in Angular 2

Angular 2 already has a very good error handler. When an error randomly occurs in your code, the Angular’s error handler will catch it and will print the error details in the console. The error details will also include the line number with a link to the source file. In most cases this should be more then enough to help you understand what is happening in your application.

Why would I need a custom error handler?

You can use a custom error handler to format the error messages that are logged into the browser’s console, to catch custom business errors in your application (Authentication/Authorization errors, HTTP 404, etc.) or maybe you want to also send the errors to you backend server for analytics or other reasons. All of the above are valid use cases of using a custom error handler.

Creating a custom error handler

Writing your own error handler is straightforward. You will need to extend Angular’s ErrorHandler class and override the handleError method. This method receives a wrapper of the original error as a parameter. You can find the original error in the error.originalError property. The default implementation uses console.error() to print the error details in the browser’s console.

CustomErrorHandler.ts

import {ErrorHandler} from '@angular/core';

export class CustomErrorHandler extends ErrorHandler {
    constructor(){
        super(false);
    }

    public handleError(error: any): void {
        // You can add your own logic here.
        // It is not required to delegate to the original implementation
        super.handleError(error);
    }
}

Extending Angular’s Error Handler

If you want to use your own custom handler you will need to somehow replace the one that Angular is using. Fortunately enough, Angular’s awesome DI engine will allows you to provide custom implementations for different classes.

AppModule.ts:

import {BrowserModule} from '@angular/platform-browser';
import {ErrorHandler} from '@angular/core';
import {AppComponent} from './app.component';

import {CustomErrorHandler} from './CustomErrorHandler';

@NgModule({
    declarations: [ AppComponent ],
    imports: [ BrowserModule ],
    bootstrap: [ AppComponent ],
    providers: [
        {provide: ErrorHandler, useClass: CustomErrorHandler}
    ]
})
export class AppModule {}

In the code above take a look at the providers field in the @NGModule decorator. With the above configuration in place, every time Angular’s DI engine will request an instance of ErrorHandler will receive an instance of our custom implementation CustomErrorHandler.

Creating custom error classes

Sometimes it’s useful to create custom error classes that you can throw in different parts of your application. For example, when the user is doesn’t have access to a specific part of the application you can throw a custom AuthorizationError.

Creating the custom error class

AuthorizationError.ts:

export class AuthorizationError {
    toString() {
        return 'You are not authorized to view this content!!!';
    }
}

Updating the CustomErrorHandler class

CustomErrorHandler.ts:

import {ErrorHandler} from '@angular/core';
import {AuthorizationError} from './AuthorizationError';

export class CustomErrorHandler extends ErrorHandler {
    constructor(){
        super(false);
    }

    public handleError(error: any): void {
        if(error.originalError instanceof AuthorizationError){
            console.info(`[CUSTOM ERROR]:::${error.originalError.toString()}`);
        } else {
            super.handleError(error);
        }
    }
}

Using the new error in your code

app.component.html:

<button (click)="throwCustomError()">Throw Authorization Error</button>

app.component.ts:

import {Component} from '@angular/core';
import {AuthorizationError} from './AuthorizationError';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  throwCustomError() {
    throw new AuthorizationError();
  }
}

Now when you press the Throw Authorization Error button you will see our custom error logging in the browser’s console:

[CUSTOM ERROR]:::You are not authorized to view this content!!!

If you look closely at the CustomErrorHandler class, everything that is not of type AuthorizationError will be delegated to the original Angular’s ErrorHandler.

Using HTTP Interceptors in Angular 2

What are HTTP Interceptors?

In Angular 1.x there was an option to register objects as HTTP Interceptors. You could then use those interceptors to perform different operations and transformations on all HTTP calls made by your application. This was a very powerful feature of the framework because not only allowed setting things like base path for the REST API endpoint, CSRF headers and many other things but also transforming or caching responses from the server.

So what’s different in Angular 2?

Well, after looking at the documentation you won’t be able to find any reference to interceptors in the new version of the framework. At least for now, interceptors are not currently supported out of the box. You could just use the classic way of doing things and just extend the HTTP class in Angular 2 but that’s not very pretty.

Introducing the XHRBackend

Angular 2 uses this class to create all HTTP connections. By taking advantage of the Angular’s great DI engine you could potentially extend the base XHRBackend class and provide our custom implementation to the application. By taking control of the creation of the HTTP connections you will be able to implement the classic Angular interceptors this way.

Let’s look at some code

Let’s start by creating our own XHRBackend.

MyXHRBackend.ts

import {XHRBackend, Request, XHRConnection, Response} from '@angular/http';
import {Observable} from 'rxjs';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

export class MyXHRBackend extends XHRBackend {

  createConnection(request: Request): XHRConnection {
    let connection: XHRConnection = super.createConnection(request);
    // Before returning the connection we try to catch all possible errors(4XX,5XX and so on)
    connection.response = connection.response.catch(this.processResponse);
    return connection;
  }

  processResponse(response:Response){
    switch (response.status) {
      case 401:
        // You could redirect to login page here
        return Observable.throw('your custom error here');
      case 403:
        // You could redirect to forbidden page here
        return Observable.throw('your custom error here');
      case 404:
        // You could redirect to 404 page here
        return Observable.throw('your custom error here');
      default:
        return Observable.throw(response);
    }
  }

}

The above XHRBackend extension will catch all 401, 403 and 404 errors.
In order to tell Angular to use our implementation instead of the default class we will use Angular’s great DI features. We just need to add our custom class to the providers list in the application main module.

AppModule.ts

import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
import {HttpModule, XHRBackend} from '@angular/http';
import {AppComponent} from './app.component';
import {MyXHRBackend} from './MyXHRBackend';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    HttpModule
  ],
  providers: [
    {provide: XHRBackend, useClass: MyXHRBackend}
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}

By providing our custom implementation of the XHRBackend, Angular’s HTTP class will use this implementation for all http calls. This means that if any http call encounters 401, 403 or 404 errors we can act accordingly in our application.

Dynamic loading of AngularJS components

Last week, I had the opportunity to speak about dynamic loading AngularJS modules and how can you achieve that using Webpack’s require.ensure method. The code and slides for the presentation can be found here. In the presentation I’ve only described how can you dynamically register router states. The basic ideea is to have some sort of mechanism to load application modules on demand and once they’re loaded, to register those new angular components in the main application in order to use them. Unfortunately, Angular register’s all of it’s components in the configuration phase so if you try to register a new directive or service after the configuration phase has ended, the component won’t be available for Angular to use.

Let’s take this simple example:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <!-- Include your required JS files here -->
        <!-- I'm using Webpack so everything is automatically included for me -->
        <title>Angular modular test app</title>
    </head>
<body>
    <!-- Use our application directive -->
    <app></app>
</body>
</html>
/**
* Create a test app.
*/
var app = angular.module('test', []);

/**
* Create an application directive
* I'm using the new Angular 1.5 syntax for components.
*/
app.component('app', {
    controller: function(){
        this.showNewDirective = false;

        // We only show the new directive after a button press.
        this.loadDirective = function(){
        this.showNewDirective = true;
        };
    },
    // In the directive template we are using an undefined directive "new-directive".
    template: '<button ng-click="$ctrl.loadDirective()" ng-if="!$ctrl.showNewDirective">Load new directive</button>
    ' +
    '<new-directive ng-if="$ctrl.showNewDirective">New directive not loaded</new-directive>'
});

The application looks like this:
Screen Shot 2016-02-29 at 12.25.57 PM
Once we press the button we will see the default “New directive not loaded” text because our “<new-directive>” was not yet defined.
Screen Shot 2016-02-29 at 12.25.45 PM

Now let’s modify our code to register the “<new-directive>” when we press the button.

app.component('app', {
    controller: function () {
        this.showNewDirective = false;

        // We only show the new directive after a button press.
        this.loadDirective = function () {
            // Register the new directive before showing it
            app.component('newDirective', {
                controller: function () {

                },
                template: '
<h1>New directive is here</h1>
'
                });
            this.showNewDirective = true;
        };
    },
    // In the directive template we are using an undefined directive "new-directive".
    template: '<button ng-click="$ctrl.loadDirective()" ng-if="!$ctrl.showNewDirective">Load new directive</button>
    ' +
    '<new-directive ng-if="$ctrl.showNewDirective">New directive not loaded</new-directive>'
});

Once you click the button again, you would expect that the new directive is showed because we registered it before we showed it. The actual result is this:

Screen Shot 2016-02-29 at 12.25.45 PM

This happens because once the config phase has ended, angular’s component method doesn’t use the same $compileProvider to register new components. With just this little piece of code added to the “App.js” file:

app.config(function ($compileProvider) {
    // Save the original $compileProvider to use it for dynamic registering
    app.component = function(name, object) {
        $compileProvider.component(name, object);
    return (this);
    };
});

If we press the button now we should see this:
Screen Shot 2016-02-29 at 3.44.58 PM

If we want this to work for all Angular’s components we need to change our config method into this:

app.config(function ($controllerProvider, $provide, $compileProvider, $filterProvider) {
    // Register directives handler
    app.component = function(name, object) {
        $compileProvider.component(name, object);
    return (this);
    };
    // Register controller handler
    app.controller = function( name, constructor ) {
        $controllerProvider.register( name, constructor );
    return( this );
    };
    // Register services handlers
    app.service = function( name, constructor ) {
        $provide.service( name, constructor );
    return( this );
    };
    app.factory = function( name, factory ) {
        $provide.factory( name, factory );
    return( this );
    };
    // Register filters handler
    app.filter = function( name, factory ) {
        $filterProvider.register( name, factory );
    return( this );
    };
});

Now you have a way to lazy load angular modules. Please don’t make your users download 5MB of javascript if they’re only going to use 2MB. Application modules like Admin, Settings, Profile, etc. should be loaded on demand.

Factory Pattern with Angular JS and ES6

angularjs

Introduction

Remember the “Gang of Four”? For those of you who don’t know, the “Gang of Four” is a group of four programmers who wrote a famous computer programming book called Design Patterns: Elements of Reusable Object-Oriented Software. In this book they talk about finding re-usable solutions to common programming problems. The Factory Pattern is a method of creating new objects without exposing the creation logic to the outside code.

Getting started

In order to implement the Factory Pattern in Angular I am going to use Angular’s factory recipe, which creates a new service using a given function. The code will be written in ES6 for simplicity but it can be easily implemented in plain old JS.

We start by creating a base object. Let’s call it Animal.

/**
 * This will be the base class for our animals.
 */
export default class Animal {
    /**
     * Construct a new Animal object
     * @param sound - The sound this animal makes.
     */
    constructor(sound) {
        this._sound = sound;
    }

    /**
     * Logs the animal sound to the console.
     */
    talk() {
        console.log(`${this.sound} !!!`);
    }

    get sound() {
        return this._sound;
    }

    set sound(value) {
        this._sound = value;
    }
}

The next step is to create concrete implementations for our animals.

import Animal from './Animal';

/**
 * Cat extends the Animal object. It will inherit all methods and properties from it.
 */
export default class Cat extends Animal {
    /**
     * Construct a new cat object
     * @param sound - Default cat sound is &amp;quot;meow&amp;quot;
     */
    constructor(sound = &amp;quot;meow&amp;quot;) {
        super(sound);
    }
}
import Animal from './Animal';

/**
 * Duck extends the Animal object. It will inherit all methods and properties from it.
 */
export default class Duck extends Animal {
    /**
     * Construct a new cat object
     * @param sound - Default duck sound is &amp;quot;quack&amp;quot;
     */
    constructor(sound = &amp;quot;quack&amp;quot;) {
        super(sound);
    }
}

Next we need to create the AnimalFactory. This class will be in charge of creating cats or ducks based on the instructions received.

import Cat from './Cat';
import Duck from './Duck';

export default class AnimalFactory {
    /**
     * This is a static method. This means we can call this method directly on the AnimalFactory class.
     * @param animalType - What type of animal we want to create.
     * @returns {Animal} - The created animal object.
     */
    static getAnimal(animalType = &amp;quot;cat&amp;quot;) {
        switch (animalType) {
            // If animalType equals &amp;quot;cat&amp;quot; we create a new Cat object.
            case 'cat':
                return new Cat();
            // If animalType equals &amp;quot;duck&amp;quot; we create a new Duck object.
            case 'duck':
                return new Duck();
            // If animalType is not supported we throw an error.
            default:
                throw new Error(`&amp;quot;${animalType}&amp;quot; is not an animal`);
        }
    }
}

Now it’s time to test our code. We need to register AnimalFactory with angular and then we can use it in our angular code to create different animals.

import angular from 'angular';

import AnimalFactory from './AnimalFactory';

// Create an angular application.
const app = angular.module('app', []);

// Register the AnimalFactory
app.factory('AnimalFactory', ()=&amp;gt;{
    return AnimalFactory;
});

// Use the factory anywhere in your angular code.
app.run((AnimalFactory)=&amp;gt;{
    // Outputs &amp;quot;meow !!!&amp;quot; because it will create a cat object.
    AnimalFactory.getAnimal('cat').talk();
    // Outputs &amp;quot;quack !!!&amp;quot; because it will create a duck object.
    AnimalFactory.getAnimal('duck').talk();
    // Outputs &amp;quot;Uncaught Error: &amp;quot;snake&amp;quot; is not an animal&amp;quot;.
    AnimalFactory.getAnimal('snake').talk();
});

As you can see, we managed to hide the actual creation of objects from the code that is using it. This is a very simple example but imagine having very complex object creation logic with different conditions. Using the Factory Pattern we are easily able to re-use and extend this piece of code.

P.S: The sample above can be easily moved to TypeScript and used with Angular 2.