left-icon

Angular 2 Succinctly®
by Joseph D. Booth

Previous
Chapter

of
A
A
A

CHAPTER 18

Getting HTTP Data

Getting HTTP Data


Many applications use a database to persist the information the application has collected. It could be Microsoft SQL Server, Oracle, or another database. In this chapter, we will cover how to consume a web service to collect some data and possibly write it back.

Web services

The HTTP protocol was designed to allow requests to be sent to web servers and responses to be retrieved from the servers. Browsers are designed to make requests of webpages, and typically bring back complete webpages to the browser. When you enter a URL in a browser address bar, such as www.syncfusion.com, the browser looks up the IP address for the website and sends a request to that website, which returns with a full HTML webpage to display to the user.

A web service operates very similarly, except rather than return a full webpage, it typically returns a small amount of formatted data that an application can then use as needed. The data is generally formatted as XML documents or a JSON string. Angular 2 works with JSON data very well, and we will look at how to communicate using JSON -oriented web services.

JSON test website

The JSON test website provides a few sample web service calls that return JSON data. For example, if you enter the URL http://ip.jsontest.com/ in your browser, you will not get a full website back, but rather a JSON string with your IP, as shown in the following code.

Code Listing 157

{"ip": "127.0.0.1"}

Angular provides the functionality to make the API request and gets the returned data into your application. There are thousands of APIs available. Many are free, but require you get an access key to use them.

JSON format

JSON (JavaScript Object Notation) is an open-source format for transmitting data objects. It is designed to be both compact and readable by humans at the same time. Although JSON is language independent, you can see its JavaScript roots.

JSON elements consist of a property name and a value, such as the IP example in Code Listing 157. A JSON object may have multiple elements. The JSON object is delimited by { }, with the collection of elements between the brackets. For example, you might represent a person with a JSON object of:

Code Listing 158

{ "name": "Jonathan" , "phone": "555-1212", "email": [email protected] }

The object is readable by both humans and computer applications. You’ve also seen some JSON files in earlier chapters as you’ve set up the Angular 2 environments.

The property values can be numeric, string, Boolean, or date. You can also have a collection of objects by nesting the objects with an outer set of { } characters.

You can make a collection of objects by providing an object name and the [ ] delimiters. Within the brackets could be multiple objects. For example, the JSON in the following code represents various phone numbers a person might have.

Code Listing 159

"PhoneNumbers" : [

         { "type": "home","areaCode": "215","number": "555-1212" },  

         { "type": "mobile","areaCode": "610","number": "867-5309" },

        ]

The JSON structure provides flexibility to be as simple or complex as your application needs it to be.

Web commands

Angular 2 provides the HTTP module that allows you to perform the following basic web methods:

  • GET: Retrieve data from a URL; query parameters can be used.
  • POST: Like GET, except parameters are passed in the request body.
  • HEAD: Like GET, but the server only returns the HTTP headers.
  • PUT: Upload a file directly to the web server.
  • DELETE: Delete a resource from the web server.

We are only going to focus on GET and POST, which are the most commonly used HTTP web requests. If you’ve designed your web service, you can support the PUT and DELETE verbs, but by their nature, they pose security risks.

Angular HTTP

Angular includes a base library called @angular/http, which contains the methods needed to make web calls. You will need to import the Http and Response modules from this library, as shown in the following code.

Code Listing 160

import {Http,Response} from '@angular/http';

Next, modify your component’s constructor to save the Http module, such as:

Code Listing 161

    constructor(private _http: Http) {

    }

This is the basic setup you will need for components that will make HTTP requests.

Root module

Since we want the HTTP services to be available throughout the application, we can add the Http module to our app.module.ts file, as shown in the following listing.

Code Listing 162

import { HttpModule }    from '@angular/http';

@NgModule({

  imports: [ BrowserModule, HttpModule],

Be sure to update your root module with these additions if they are not already there.

Web service

You should generally wrap the web calls in a service so they can be used by different components as needed. For example, we are going to create a WebService class to handle all the HTTP calls. You could import the WebService as a provider and save it to a private variable during the constructor code.

Code Listing 163

import { WebService } from './services/WebService';

  @Component({

    providers: [SoccerService,WebService]           

   })

export class AppScoring {

     public constructor( private _web: WebService ) { }

At this point, the component has access to the service and will be able to use any of the methods the web service chooses to provide. For our example, we are simply going to call the IP method from the JSON test website and display the IP address in our template. With a few tweaks, you could easily use this service to restrict access to certain sections of the template to a whitelist of acceptable IP addresses.

Creating the web service

The web service will handle the actual interaction with the sites or API you wish to use. You should start with the appropriate imports from the Angular libraries and from the Reactive Extensions (RxJS) library.

Note: The Angular 2 HTTP services rely on JavaScript observables, which is what the RxJS libraries are designed to handle. In general, an observable is a way to allow JavaScript to run asynchronously.

Web service imports

The WebService class will need the following imports to set up HTTP and the observables.

Code Listing 164

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

import { Http,Response}  from '@angular/http';

import { Observable }    from 'rxjs/Rx';

import 'rxjs/Rx';

Since it is a service, we will need to make it injectable and save the Http module during the constructor.

Code Listing 165

@Injectable()

export class WebService {

    constructor(private _http: Http) {

    }

With this basic setup, we can start adding the various methods to make HTTP calls. Our first method will call the ip.jsontest web service to get the IP address of the site visitor. This could be useful for logging purposes or to whitelist access to certain areas of the website.

Code Listing 166

    private _IPURL: string = "http://ip.jsontest.com";

    public getIP (): Observable<string> {

        return  this._http.get(this._IPURL)

                        .map(this.extractIP)

   }

The Observable and map functions come from the RxJS library. An error message of Map undefined would indicate that the RxJS library is not loaded. You could also create private a method to extract the data elements from the returned JSON object. In our example, the private method (ExtractIP) gets the IP string field from the JSON object the call returns.

Code Listing 167

    private extractIP(res: Response) :string {

        let body = res.json();

        return body.ip || { };

    }

You will likely need different methods to extract object properties, depending on the structure of the JSON data that is being returned.

Using the service

Assuming your component refers to the service as _web, we need to perform two steps. First is to declare a component property to hold the results from the service.

Code Listing 168

  public IPAddr: string;

The second step is to subscribe to the service method. Keep in mind that the web service is called asynchronously, so your TypeScript code will keep going after the call to the getIP() method. The subscribe() method is basically telling the method: go off and do your thing, but I want you to do something as soon as you are done—in this case, simply put the results into my variable.

Code Listing 169

_web.getIP().subscribe( IP => this.IPAddr = IP);

Once the getIP() method completes (and returns the IP address), we tell the method to take the results and put it into our IPAddr variable. In this, we are getting a simple string. We could also define a class that matches the web service JSON structure and have the service copy the entire JSON structure into an object created from our class.

Passing parameters

There are two ways to pass parameters to a web service. You can pass them on the GET query string if the parameters are part of the URL. For example, the jsontest site has a service that will compute an MD5 from a given text string. If we pass the following URL:

Code Listing 170

md5.jsontest.com?text=Angular2Rocks

The site will return a JSON string, as shown in the following code.

Code Listing 171

{

   "md5": "c2690756861ba21dc367ab72b0621906",

   "original": "Angular2Rocks"

}

The only caveat to keep in mind is that the parameters passed on the query string must be URL-encoded. Fortunately, TypeScript includes a function that allows us to easily do that.

Code Listing 172

    public getMD5( str: string) : Observable<string> {

        let finalUrl = this._MD5URL + encodeURI(str);   

        return  this._http.get(finalUrl)

                        .map(this.extractMD5);

    }

The rest of the code to use the GET method and a query string parameter is the same. Don’t forget the custom extraction method to get the proper JSON parameter.

Post method

A second technique to pass parameters to a web service is via the POST method. When you use POST, it hides the parameters from casual users (since they are not visible on the query string), and it allows larger parameter sizes. (Query string length is generally limited to 2048 bytes, although this varies by browser.)

When using a POST method, you will need to include some additional modules for building the request.

Code Listing 173

import { Headers, RequestOptions } from '@angular/http';

The Headers are used to tell the web service the type of data we are sending, in this case, JSON data. The RequestOptions are used to construct the data request to be sent to the web service.

To build the request, you will need to create both the headers and the request options, as shown in the following sample. The content type of application/json tells the service to expect JSON data.

Code Listing 174

FindZipCity (zipCode: string): Observable<string> {

    let headers = new Headers({ 'Content-Type': 'application/json' });

    let options = new RequestOptions({ headers: headers });

The actual call is like a GET method, except for the extra parameters of the JSON data and the request options.

Code Listing 175

return this.http.post(this.heroesUrl, { zipCode }, options)

                    .map(this.extractCity)

You would need to write your own extractCity method, or perhaps create a class to get all the information returned by the web service.

Error handling

No matter which method you are using, GET or POST, you should add code to check for any errors that might occur. The error handler is a private method in the web service. You only need one, and can attach it to any of the calls.

Code Listing 176

private handleError (error: Response | any) {

  let errMsg: string;

  if (error instanceof Response) {

    const body = error.json() || '';

    const err = body.error || JSON.stringify(body);

    errMsg = `${error.status} - ${error.statusText || ''} ${err}`;

  } else {

    errMsg = error.message ? error.message : error.toString();

  }

  return Observable.throw(errMsg);

}

To attach the error handler to the method calls, you chain a catch method after the map call, and pass the error handling method. For example:

Code Listing 177

    public getMD5( str: string) : Observable<string> {

        let finalUrl = this._MD5URL + encodeURI(str);   

        return  this._http.get(finalUrl)

                        .map(this.extractMD5)

                    .catch(this.handleError);

    }

Your component code can access the error by checking for it during the subscribe call, as shown in the following code example.

Code Listing 178

_web.getIP().subscribe( IP => this.IPAddr = IP,

Error => this.ErrMsg = Error);

This will copy the error message to the component string property called ErrMsg. You could optionally display it in your template using the *ngIf directive, but the error message might not be meaningful to the end user.

Summary

The HTTP module makes web service and API calls simple— just remember that the calls are asynchronous, so you need to subscribe to get the results. This will allow your application to run quickly, even as it reaches out to other sites for JSON information.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.