Corredor

ウェブ、プログラミングの勉強メモ。

Angular v4.3 で追加された HttpClient を使ってみた

はじめてのAngular4 (I・O BOOKS)

はじめてのAngular4 (I・O BOOKS)

Angular v4.3 で新たに追加された HttpClient というモジュールを使ってみた。

これは既存の Http モジュールとは別モノで提供されていて、JSON のパースを勝手にやってくれたり、レスポンスの型指定ができたりと便利なようなので、ちょっとだけ使ってみた。

Angular v4.3 プロジェクトを用意する

前提環境は Angular CLI で作れる Angular アプリの雛形相当。これに Angular v4.3 のモジュール群をインストールする。

Angular は毎週パッチバージョンが上がるので、執筆時点では v4.3.2 になっている。npm outdated でバージョンを確認し、npm update@angular の各パッケージを v4.3.2 にアップデートする。npm-check-updates というパッケージを使えば一気に更新できるので、これをグローバルインストールして ncu -a とするのが楽かも。

HttpClient モジュールを追加する

次にアプリのモジュールに HttpClient モジュールを追加する。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';  // ← コレ

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule  // ← コレ
  ],
  // 以下略
})
export class AppModule {}

HttpClient を使用するサービスを作る

次に HttpClient を使用するサービスを作る。ココでは GET・POST 通信をそれぞれ行うメソッドを用意した。

import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';

/**
 * GET・POST 通信を行うサンプル
 */
@Injectable()
export class SampleService {
  /**
   * コンストラクタ
   *
   * @param http HttpClient を DI する
   */
  constructor(private http: HttpClient) { }

  /**
   * GET 通信のサンプル
   *
   * @return GET 通信の結果を持った Promise
   */
  get(): Promise<any> {
    const url = 'http://example.com/sample-api';
    const myParameter = 'MyParameterValue';

    return this.http.get(url, {
      params: new HttpParams().set('myParameter', myParameterValue);
    }).toPromise();
  }

  /**
   * POST 通信のサンプル

   * @return POST 通信の結果を持った Promise
   */
  save(): Promise<any> {
    const url = 'http://example.com/sample-api';
    const body = {
      myPostData: 'MyPostDataValue'
    };

    return this.http.post(url, body).toPromise();
  }
}

GET 通信のサンプル

一番簡単な GET 通信のサンプルは以下のとおり。

this.http.get(url)
  .subscribe((response) => {
    // response は Object 型
  });

これで指定の URL に GET 通信ができる。

これまでの Http モジュールは戻り値が Observable<Response> であり、JSON パースする必要があったが、HttpClient では Observable<Object> で返されるので JSON パースが要らなくなった。

上述の SampleService では、パラメータを指定している他、Observable を Promise に変換している。以下のように扱うことができる。

this.http.get(url, {
  params: new HttpParams().set('myParameter', 'MyParameterValue');
  // レスポンスのフォーマットを指定する場合は以下
  responseType: 'text'
})
  .toPromise()
  .then((response) => {
    // 処理
  });

これで、【url】?myParameter=MyParameterValue という URL で GET 通信したのと同じ結果が得られる。

POST 通信のサンプル

POST 通信の場合も、基本的なやり方は同じ。

this.http.post(url, {
  myPostData: 'MyPostDataValue'
})
  .subscribe((response) => {
    // 成功
  }, (error) => {
    // 失敗
  });

GET パラメータに対応する、POST 時の body は Object で記せば良い。

これも SampleService の方では Promise 化している。

this.http.post(url, body)
  .toPromise()
  .then((response) => {
    // 成功
  })
  .catch((error) => {
    // 失敗
  });

ユニットテストのやり方

HttpClient モジュールはユニットテストでのモック化も楽になっている。少しだけつまづいたところがあるので紹介。

import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';

import { SampleService } from './sample.service';

describe('SampleService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [SampleService]
    });
  });
  
  // テスト対象サービス
  let sut;
  // 通信先のモック
  let httpMock
  // テスト対象サービス・モックの用意
  beforeEach(inject([SampleService, HttpTestingController], (sampleService: SampleService, httpTestingController: HttpTestingController) => {
    sut = sampleService;
    httpMock = httpTestingController;
  }));
  
  it('GET 通信を行う', () => {
    // アクセスを期待する URL : HttpParams を指定している場合はパラメータを含めて URL とする
    const url = 'http://example.com/sample-api?myParameter=MyParameterValue';
    // モックの戻り値
    const result = 'Mock GET Result';
    
    // テスト対象関数の実行
    sut.get()
      .then((data) => {
        // モックとして返却したデータが受け取れていること
        expect(data).toEqual(result);
      })
      .catch((error) => {
        fail(`GET 通信のテストに失敗 : ${error}`);
      });
    
    // モック API を用意する
    const request = httpMock.expectOne(url);
    // モック API からの応答を返す
    request.flush(result);
    // モック化した API がコールされたか検証する
    httpMock.verify();
  });
  
  it('POST 通信を行う', () => {
    // アクセスを期待する URL
    const url = 'http://example.com/sample-api';
    // モックの戻り値
    const result = 'Mock POST Result';
    
    // テスト対象関数の実行
    service.post()
      .then((data) => {
        // モックとして返却したデータが受け取れていること
        expect(data).toEqual(result);
      })
      .catch((error) => {
        fail(`POST 通信のテストに失敗 : ${error}`);
      });
    
    // モック API を用意する
    const request = httpMock.expectOne(url);
    // モック API からの応答を返す
    request.flush(result);
    // モック化した API がコールされたか検証する
    httpMock.verify();
  });
});
  • テスト時は HttpClientTestingModuleimports に指定する。
  • HttpTestingController がモック API を担当する。HttpTestingController#expectOne() の引数に指定した URL に対してアクセスがあれば OK となる。
  • GET 通信にパラメータを指定している場合は、パラメータを含めて URL が一致しないとテストが通らない。
  • HttpTestingController#verify() で、「アクセスを待ち構えていたけど呼ばれなかった URL」が分かったりする。

こんな感じ。他にも色々便利な機能があるっぽいけど、新しすぎて文献不足。

参考

「Observable って何?」という方は以下などをドウゾ。簡単に言うと高機能 Promise。