この記事は、Business Bank Group Developers Advent Calendar 3日目の記事です。
こんにちは、ビジネスバンクグループでエンジニアをしているしみきょん @kyokoshimizu です。
今Angularのversionを6にアップデートしようとしているのですが、その前に必須となるHttp -> HttpClient 移行した話を書きます
移行作業
もともと、HttpModuleを使用してHTTPリクエストを行なっていた処理を、HttpClient, HttpClientModuleを使用するようにしました。
// import { HttpModule } from '@angular/http';
import { HttpClient, HttpClientModule } from '@angular/common/http';
もともと、こんな感じだったHTTPリクエスト用のServiceが
import { Headers, Http, URLSearchParams } from '@angular/http';
export interface HttpOptionsInterface {
params: any;
body: any;
...
}
export class BaseService {
constructor(private http: HttpClient) {}
search<Hoge>(url: string, options?: HttpOptionsInterface): Observable<Hoge> {
const headers = this.getHeaders(options.header);
const params = this.getSearchParams(options.params);
return this.http.get(url, Object.assign({ headers: headers, params: params }))
.map(res => res.json() as Hoge);
}
...
protected getHeaders(options: any = {}): Headers { ... } // 認証トークンやContent-Typeのセット
protected getSearchParams(params: any): URLSearchParams { .. } // リクエストパラメータのセット
}
こんな感じに変わりました
import { HttpClient, HttpParams } from '@angular/common/http';
export interface HttpOptionsInterface {
params: any;
body: any;
...
}
export class BaseService {
constructor(private http: HttpClient) {}
search<Hoge>(url: string, options?: HttpOptionsInterface): Observable<Hoge> {
return this.http.get<Hoge>(url, { params: this.getSearchParams(options.params) });
}
...
protected getSearchParams(params: any): HttpParams { .. }
}
レスポンスがJSONオブジェクトとして返却されるようになりました
そのため、レスポンスを.jsonする必要がなくなりました。
またメソッドを呼ぶ際に型パラメータを指定することによって、レスポンスオブジェクトの型定義もできます。
this.http.get<Hoge> // -> Observable<Hoge>
responseTypeを指定することによって、JSON以外のデータをリクエストすることも可能です。
リクエスト処理が失敗した時は、HttpErrorResponseが返却されます。
リクエスト周りの変更点
Headers -> HttpHeaders
URLSearchParams -> HttpParams
になりました。
HttpParamsはimmutableです。
HttpParamsOptionsというオプションがあって
new HttpParams({fromObject: { hoge: 1, hoge: 2 }})
みたいなことができるのですがAngular5以降しかfromObjectオプションがないので、Angular4環境で作業していた私は使用できませんでした。。
string, 配列, オブジェクトの3パターンの値をHttpParamsにセットしたかったので現状こんな感じになってます
(Angular6にしたらリファクタリングする予定です)
let urlSearchParams = new HttpParams();
_.each(params, (val, key) => {
if (val instanceof Array) {
_.each(val, (v) => urlSearchParams = urlSearchParams.append(key.toString(), v));
} else {
const value = (val instanceof Object) ? JSON.stringify(val) : val;
urlSearchParams = (_.isUndefined(value) || _.isNull(value)) ?
urlSearchParams.delete(key.toString()) : urlSearchParams.append(key.toString(), value);
}
});
RequestOptionsArgsはなくなり、HttpClient#get, HttpClient#deleteにはbodyを渡せなくなったのでgetやdeleteにbodyを渡したい時は、HttpClient#requestを使用するようにしました。
Interceptor
インターセプターという機能が追加されました。
HttpInterceptorを実行したclassにinterceptメソッドを書くと、リクエストとレスポンス時に処理をフックすることができます。
今回は、もともとgetHeadersで行なっていたheader情報の挿入をinterceptorに切り出しました。
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
@Injectable()
export class DefaultRequestInterceptor implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
const newReq = req.clone({
setHeaders: { 'Content-Type': 'application/json' }
});
return next.handle(newReq);
}
interceptor便利です!
まとめ
以上、HttpClient移行の話でした。インターセプターは今後も色々と活用していきたいなと思います!
日本語公式ドキュメント 丁寧に説明されていてわかりやすかったです
明日は、 @bigplants さんが担当です!
お願いします!