close icon
Angular

Using Angular $Http and Angular 2 Http - Angular 2 Series Part 3

Learn the differences between $http in Angular 1.x and Http in Angular 2. Find out how to use the RxJS Observables that Http returns.

October 15, 2015

--- TL;DR: Making HTTP requests in Angular 2 apps looks somewhat different than what we're used to from Angular 1.x, a key difference being that Angular 2's Http returns observables. In this tutorial, we cover how to use Http to make requests and how to handle the responses. We'll also see how we can do basic authentication for an Angular 2 app. Check out the repo for the tutorial to see the code.

This is Part 3 in our Angular 2 series. Be sure to check out Part 1 on Pipes and Part 2 on Models.


It's fair to say that most of Angular 2 looks and feels completely different than Angular 1.x, and the Http API is no exception. The $http service that Angular 1.x provides works very nicely for most use cases, and is fairly intuitive to use. Angular 2's Http requires that we learn some new concepts, including how to work with observables.

In this tutorial, we'll look at some of the key differences in the way that Angular 1.x and 2 implement HTTP requests, and we'll also see how to make requests and handle responses. Incidentally, the sample we use to test out Http will also let us see the basics of adding authentication to an Angular 2 app.

It's important to note that the Http implementation for Angular 2 is still a work in progress, and a lot of things are still in flux or aren't complete yet.

Differences between Angular 1.x $http and Angular 2 Http

Angular 2's Http implementation again provides a fairly straightforward way of handling requests, but there are some key differences. For starters, HTTP calls in Angular 2 by default return observables through RxJS, whereas $http in Angular 1.x returns promises. Using observable streams gives us the benefit of greater flexibility when it comes to handling the responses coming from HTTP requests. For example, we have the potential of tapping into useful RxJS operators like retry so that a failed HTTP request is automatically re-sent, which is useful for cases where users have poor or intermittent network communication. We'll see later in the article how we can implement RxJS operators in our Http observables.

In Angular 2, Http is accessed as an injectable class from angular2/http and, just like other classes, we import it when we want to use it in our components. Angular 2 also comes with a set of injectable providers for Http, which are imported via HTTP_PROVIDERS. With these we get providers such as RequestOptions and ResponseOptions, which allow us to modify requests and responses by extending the base class for each. In Angular 1.x, we would do this by providing a transformRequest or transformResponse function to our $http options.

In Angular 1.x we can transform requests globally in the application's config.

.config(function($httpProvider) {
  $httpProvider.defaults.transformRequest = function(data) {
    return JSON.stringify({name: "Ryan"});
  }
});

Whereas in Angular 2, we would extend the BaseRequestOptions.

class MyOptions extends BaseRequestOptions {
  body: string = JSON.stringify({name: "Ryan"});
}

bootstrap(App, [HTTP_PROVIDERS, provide(RequestOptions, {useClass:MyOptions})]);

Http in Action

Let's take a look at how we can perform some basic requests with Http. We'll see how to work with POST and GET requests by using our trusty NodeJS Chuck Norris quote backend, which will require us to retrieve and store a JWT, and thereby implement basic authentication.

Getting Started

As we have in our other Angular 2 articles, we'll use Pawel Kozlowski's ng2-play repo for this tutorial. To get started, clone the repo and run npm install, then gulp play.

We also need to get our random quote server running. With the Angular 2 seed project installed, let's clone and install the quote server in the root of our project.

We also need to set up our app component by importing what we need and providing a template.

// app.ts

import {Component, View} from 'angular2/angular2';
import {Http, Headers} from 'angular2/http';
import {CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/angular2';

@Component({
  selector: 'app'
})

@View({
  directives: [ CORE_DIRECTIVES, FORM_DIRECTIVES ],  
  template: `
  <header>
    <h1 class="title">Angular 2 HTTP</h1>
  </header>

  <section>
    <h2>Login</h2>
    <form #f="form" (ng-submit)="authenticate(f.value)">
      <div ng-control-group="credentials">
          <label for="username">Username</label>
          <input
            type="text"
            id="username"
            ng-control="username"
            required>

          <label for="password">Password</label>
          <input
            type="password"
            id="password"
            ng-control="password"
            required>
      </div>

      <button>Login!</button>

    </form>

  </section>

  <section>
    <h2>Random Quote</h2>
    <hr>
      <h3>{{ "{{randomQuote" }}}}</h3>
    <button (click)="getRandomQuote()">Get Random Quote!</button>
  <section>

  <section>
    <h2>Secret Quote</h2>
    <hr>
    <h3>{{ "{{secretQuote" }}}}</h3>
    <button (click)="getSecretQuote()">Get Secret Quote!</button>
  <section>
  `
})

export class App {

  constructor(public http: Http) {

  }

}

bootstrap(App, [HTTP_BINDINGS])

As you can see, we've imported some familiar pieces like Component and View, but we are also pulling in Http and Headers. We'll see it later on, but we can modify the headers we send in our requests with the Headers class.

We're making use of a form for the user to eventually provide their credentials. The form calls an authenticate method on submit.

In the App class, we're passing Http to the constructor so that we can use it in our class methods.

Simple GET Request

Let's start with a simple GET request to the api/random-quote route which doesn't require authentication.

getRandomQuote() {
  this.http.get('http://localhost:3001/api/random-quote')
    .map(res => res.text())
    .subscribe(
      data => this.randomQuote = data,
      err => this.logError(err),
      () => console.log('Random Quote Complete')
    );
}

logError(err) {
  console.error('There was an error: ' + err);
}

The getRandomQuote method starts off looking pretty familiar--we do an http.get request by passing in a URL as an argument. Remembering $http from Angular 1.x, this is where we would tap into the promise that gets returned by using .then, but as you can see here, we're doing something pretty different.

As was mentioned earlier, HTTP calls in Angular 2 return observables, so we need to use RxJS methods to operate on them. The first thing we do is map the values that are returned as text, since our call to the api/random-quote endpoint returns text. If we were expecting a JSON response, we would call res.json() instead. After this, we need to subscribe to it so that we can observe values that are returned.

"HTTP calls in Angular 2 return observables, so we need to use RxJS methods to operate on them."

Tweet

Tweet This

An observable subscription takes three functions to handle what happens as the stream is observed. The first function is the next case, or what happens when the HTTP call is successful. If the call is successful, we're saying that the data returned should be put on a property randomQuote so it can be displayed in the view. The second function is the error case, and in our example we are logging any error messages to the console by calling our logError method. Finally, the third function defines what happens once the call is complete, and here we are simply logging out the things are finished.

Let's test that out to make sure it works.

angular2 http $http example

POST Request with Modified Content Type

Our authenticate method will need to make a POST request to the back end and specify the content type so that we can send our credentials. For this, we'll use Headers.

// app.ts

...

class CredentialsModel {
  username: string;
  password: string;
}

...

authenticate(data) {
  var username = data.credentials.username;
  var password = data.credentials.password;

  var creds = "username=" + username + "&password=" + password;

  var headers = new Headers();
  headers.append('Content-Type', 'application/x-www-form-urlencoded');

  this.http.post('http://localhost:3001/sessions/create', creds, {
    headers: headers
    })
    .map(res => res.json())
    .subscribe(
      data => this.saveJwt(data.id_token),
      err => this.logError(err),
      () => console.log('Authentication Complete')
    );
}

saveJwt(jwt) {
  if(jwt) {
    localStorage.setItem('id_token', jwt)
  }
}

...

The authenticate method accepts data that is passed down from the view when the form is submitted. We're grabbing the username and password from it and making a creds string in the form that the server expects.

We need to say that the content type should be application/x-www-form-urlencoded and this can be done by appending a header onto our headers instance. Then we simply pass this as a header in the options object when we make the POST request. From here, the returned observable is handled in the same way that we saw in the GET request, but this time the response is JSON, so we use res.json(). We also call the saveJwt method and pass it the token that is received to save it in local storage.

GET Request with Authorization Header

Now that we know how to modify headers, sending the JWT as an Authorization header is simple.

// app.ts

...

getSecretQuote() {

  var jwt = localStorage.getItem('id_token');
  var authHeader = new Headers();
  if(jwt) {
    authHeader.append('Authorization', 'Bearer ' + jwt);      
  }

  this.http.get('http://localhost:3001/api/protected/random-quote', {
    headers: authHeader
  })
  .map(res => res.text())
  .subscribe(
    data => this.secretQuote = data,
    err => this.logError(err),
    () => console.log('Secret Quote Complete')
  );

}

...

We can check this in the browser to make sure our call to the protected endpoint works.

angular2 http $http observables rxjs

What Can We Do with Observables?

You might be wondering why Http doesn't just return promises like it used to, so we can stick to our familiar methods for resolving HTTP calls. The fact of the matter is that we can do much more with observables than promises. With observables, we have a whole bunch of operators to pull from, which let us customize our streams in nearly any way we want.

If you haven't worked with observables before, you can get an idea of how they work in our recent post on Authenticable Observables.

It should be noted that the Angular team is still deciding on the best way of implementing the RxJS operators with Http, which means these operators aren't all available for use just yet.

We can get a taste for how they work by plugging in some simple operators. For example, in our GET call to api/random-quote, we can attach a filter.

// app.ts

...

getRandomQuote() {
  var count = 0;
  this.http.get('http://localhost:3001/api/random-quote')
    .map(res => res.text())
    .filter(x => x.length > 100)
    .subscribe(
      data => this.randomQuote = data,
      err => this.logError(err),
      () => console.log('Random Quote Complete')
    );
}

...

Now only quotes with a length greater than 100 characters will come through. If we click the "Get Random Quote" button a few times, we see it at work.

We can also delay our subscription if we want. Here we wait two seconds before printing the quote to the screen.

// app.ts

...

  .map(res => res.text())
  .delay(2000)
  .subscribe(
    data => this.randomQuote = data,
    err => this.logError(err),
    () => console.log('Random Quote Complete')
  );

...

While that might not be the most useful, what we will really benefit from once Http is solidified are operators like retry. If we were expecting network connectivity issues, we could define a number of times to retry the request.

// app.ts

...

  .retry(3)
  .map(res => res.text())
  .subscribe(
    data => this.randomQuote = data,
    err => this.logError(err),
    () => console.log('Random Quote Complete')
  );

...

Another benefit of observables is that they can be cancelled. This can be useful for situations where HTTP requests are going on for a long time, perhaps to an unresponsive server somewhere. This is something that isn't easily done with promises, and something that the Fetch API has yet to implement.

Aside: Using Angular with Auth0

Auth0 issues JSON Web Tokens on every login for your users. This means that you can have a solid identity infrastructure, including single sign-on, user management, support for social identity providers (Facebook, Github, Twitter, etc.), enterprise identity providers (Active Directory, LDAP, SAML, etc.) and your own database of users with just a few lines of code. We implemented a tight integration with Angular 1. Angular 2 integration is coming as soon as it's on Beta! You can read the documentation here or you can checkout the SDK on Github.

Wrapping Up

HTTP requests in Angular 2 definitely look different than they did in Angular 1.x, but with the change comes a big boost in capability. Having requests return observables is great because we will be able to use RxJS's operators to get the returned streams behave the way we like. We'll be able to use operators like retry to automatically start a request again if there are network issues.

In this tutorial we saw how Http can be used to make GET and POST requests, but we can also use other HTTP verbs like PUT, DELETE, and PATCH. We also saw how we can customize the headers we send with the Headers class.

As with Angular 2 in general, Http is always going through changes. The Angular team keeps a very good backlog of Http issues and feature implementations, which is a good place to keep updated on how Http progresses.

  • Twitter icon
  • LinkedIn icon
  • Faceboook icon