Book Image

MEAN Blueprints

By : Robert Onodi
Book Image

MEAN Blueprints

By: Robert Onodi

Overview of this book

The MEAN stack is a combination of the most popular web development frameworks available—MongoDB, Angular, Express, and Node.js used together to offer a powerful and comprehensive full stack web development solution. It is the modern day web dev alternative to the old LAMP stack. It works by allowing AngularJS to handle the front end, and selecting Mongo, Express, and Node to handle the back-end development, which makes increasing sense to forward-thinking web developers. The MEAN stack is great if you want to prototype complex web applications. This book will enable you to build a better foundation for your AngularJS apps. Each chapter covers a complete, single, advanced end-to-end project. You’ll learn how to build complex real-life applications with the MEAN stack and few more advanced projects. You will become familiar with WebSockets and build real-time web applications, as well as create auto-destructing entities. Later, we will combine server-side rendering techniques with a single page application approach. You’ll build a fun project and see how to work with monetary data in Mongo. You will also find out how to a build real-time e-commerce application. By the end of this book, you will be a lot more confident in developing real-time, complex web applications using the MEAN stack.
Table of Contents (13 chapters)
MEAN Blueprints
Credits
About the Author
About the Reviewer
www.PacktPub.com
Preface
Index

Granting access to our application


We have restricted access to our API's endpoints, so now we have to grant users sign-in functionality from the client application. I like to group the Angular 2 application files based on their domain context. So, for example, all our authentication, registration, and business logic should go into a separate folder; we can call it auth.

If your module directory grows, it's good practice to break it down into separate folders based on their context by type. There is no magic number for the file count. Usually, you will get a good feeling when it's time to move files around. Your files should always be easy to locate and give you enough information from their placement in a certain context.

AuthService

We are going to use AuthService to implement the data access layer and make calls to the backend. This service is going to be the bridge between our API's sign-in and register features. Create a new file called contact-manager/src/auth/auth.service.ts, and add the following TypeScript code into it:

import { Injectable } from 'angular2/core';
import { Http, Response, Headers } from 'angular2/http';
import { contentHeaders } from '../common/headers';

@Injectable()
export class AuthService {
  private _http: Http;

  constructor(http: Http) {
    this._http = http;
  }
}

We import the necessary modules, define the AuthService class, and export it. The Injectable marker metadata will mark our class to be available to be injected. In order to communicate with the backend, we use the HTTP service. Don't forget to add the HTTP_PROVIDERS when bootstrapping the application so that the service is available to be injected in the whole application.

To sign in a user, we are going to add the following method:

  public signin(user: any) {
    let body = this._serialize(user);

    return this._http
    .post('/auth/signin', body, { headers: contentHeaders })
    .map((res: Response) => res.json());
  }

We can use the .map() operator to transform the response into a JSON file. When performing HTTP requests, this will return an Observable. You have probably already figured it out—we are going to use RxJs (Reactive Extensions) heavily, which is a third-party library favored by Angular.

RxJs implements asynchronous observable pattern. In other words, it enables you to work with asynchronous data streams and apply different operators. Observables are used widely in Angular applications. At the time of writing this book, Angular 2 exposes a stripped-down version of the Observable module from RxJs.

Don't worry; we'll get familiar with this technique and the benefits of it as we dive further into the book. Now let's continue with the rest of the missing methods we want to expose:

  public register(user: any) {
    let body = this._serialize(user);

    return this._http
    .post('/auth/register', body, { headers: contentHeaders })
    .map((res: Response) => res.json());
  }

  private _serialize(data) {
    return JSON.stringify(data);
  }

We added the register() method to our service, which will handle user registration. Also note that we moved our serialization into a separate private method. I've left this method in the same class so that it's easier to follow, but you can move it into a helper class.

User sign-in component

For a start, we are going to implement the sign-in component. Let's create a new file called contact-manager/public/src/auth/sigin.ts and add the following lines of TypeScript code:

import { Component } from 'angular2/core';
import { Router, RouterLink } from 'angular2/router';
import { AuthService } from './auth.service';

export class Signin {
  private _authService: AuthService;
  private _router: Router;

  constructor(
    authService: AuthService,
    router: Router
  ) {
    this._authService = authService;
    this._router = router;
  }

  signin(event, email, password) {
    event.preventDefault();

    let data = { email, password };

    this._authService
    .signin(data)
    .subscribe((user) => {
      this._router.navigateByUrl('/');
    }, err => console.error(err));
  }
}

We still need to add the Component annotation before our Signin class:

@Component({
    selector: 'signin',
    directives: [
      RouterLink
    ],
    template: `
      <div class="login jumbotron center-block">
        <h1>Login</h1>
        <form role="form" (submit)="signin($event, email.value, password.value)">
          <div class="form-group">
            <label for="email">E-mail</label>
            <input type="text" #email class="form-control" id="email" placeholder="enter your e-mail">
          </div>
          <div class="form-group">
            <label for="password">Password</label>
            <input type="password" #password class="form-control" id="password" placeholder="now your password">
          </div>
          <button type="submit" class="button">Submit</button>
          <a href="#" [routerLink]="['Register']">Click here to register</a>
        </form>
      </div>
    `
})

The Signin component is going to be our sign-in form and it uses the AuthService to communicate with the backend. In the component's template, we are using local variables marked with a # sign for the email and password fields.

As we said earlier, the HTTP service returns an Observable when making a request. This is the reason we can subscribe to the response generated by the requests made from our AuthService. On successful authentication, the user is redirected to the default home path.

The Register component will look similar to the Signin component, so there is no need to detail this scenario. The final version of the auth module will be available in the source code.

Custom HTTP service

In order to restrict access to our API endpoints, we have to make sure that, if a request is unauthorized, we redirect the user to the sign-in page. Angular 2 has no support for Interceptors and we don't want to add a handler for each request we integrate into our services.

A more convenient solution would be to build our own custom service on top of the built-in HTTP service. We could call it AuthHttp, from authorized HTTP requests. Its purpose would be to check whether a request returned a 401 Unauthorized HTTP status code.

I would like to take this thought even further and bring a hint of reactive programming, because we are already using RxJS. So, we can benefit from the full set of functionalities it provides. Reactive programming is oriented around data. Streams of data propagate in your application and it reacts to those changes.

Let's get to business and start building our custom service. Create a file called contact-manager/public/src/auth/auth-http.ts. We are going to add a few lines of code:

import { Injectable } from 'angular2/core';
import { Http, Response, Headers, BaseRequestOptions, Request, RequestOptions, RequestOptionsArgs, RequestMethod } from 'angular2/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { BehaviorSubject } from 'rxjs/Subject/BehaviorSubject';

@Injectable()
export class AuthHttp {
  public unauthorized: Subject<Response>;
  private _http: Http;

  constructor(http: Http) {
    this._http = http;
    this.unauthorized = new BehaviorSubject<Response>(null);
  }
}

There are a few things we imported at the top of the file. We'll need all of them in this module. We defined a public property named unauthorized, which is a Subject. A Subject is both an Observable and Observer. This means that we can subscribe our subject to a backend data source and also all observers can subscribe to the subject.

In our case, the subject will be a proxy between our data source and all the subscribed observers. If a request is unauthorized, all subscribers get notified with the change. This enables us to just subscribe to the subject and redirect the user to the sign-in page when we detect an unauthorized request.

To succeed in doing this, we have to add a few more methods to our AuthHttp service:

  private request(requestArgs: RequestOptionsArgs, additionalArgs?: RequestOptionsArgs) {
    let opts = new RequestOptions(requestArgs);

    if (additionalArgs) {
      opts = opts.merge(additionalArgs);
    }

    let req:Request = new Request(opts);

    return this._http.request(req).catch((err: any) => {
      if (err.status === 401) {
        this.unauthorized.next(err);
      }

      return Observable.throw(err);
    });
  }

The preceding method creates a new request with the desired RequestOptions and invokes the request method from the base HTTP service. Additionally, the catch method captures all requests with status code not 200-level.

Using this technique, we can send the unauthorized request to all subscribers by using our unauthorized subject. Now that we have our private request method, we just need to add the rest of the public HTTP methods:

  public get(url: string, opts?: RequestOptionsArgs) {
    return this.request({ url: url, method: RequestMethod.Get}, opts);
  }

  public post(url: string, body?: string, opts?: RequestOptionsArgs) {
    return this.request({ url: url, method: RequestMethod.Post, body: body}, opts);
  }

  public put(url: string, body?: string, opts?: RequestOptionsArgs) {
    return this.request({ url: url, method: RequestMethod.Put, body: body}, opts);
  }

  // rest of the HTTP methods ...

I've added only the most commonly used methods; the rest is available in the full version. The preceding code calls our request method and sets the necessary options for each request type. Theoretically, we have created a façade to handle unauthorized requests.

I think we've made good progress and it's time to move on to the rest of the modules of our contact manager application.