【ionic2】apiリクエストをproviderで共通処理化する

はじめに

今回やりたかったことは以下
APIのURLを開発と本番で切り替えられるようにしたい
・アプリ全体で認証トークンをhttpヘッダーに含めたい

これらを満たすAPIリクエストの共通処理実装したのでメモしておく。

APIのURLを開発と本番で切り替える

こちらのURLのとおりにやったらできた。
http://roblouie.com/article/296/ionic-2-environment-variables-the-best-way/

webpackの設定とかはURLのとおりにやればできる。あとは以下のように各々呼び出せるようになる。

import { Injectable, Inject } from '@angular/core';
import { EnvVariables } from '../app/environment-variables/environment-variables.token';

@Injectable()
export class ApiService {

  constructor(http: Http, @Inject(EnvVariables) public envVariables) {
  }

  test() {
    // this.envVariables.apiEndpoint
  }
}

今回は上の記事に書いてあるそのまんまつかわせてもらった。

src/app/environment-variables/development.ts

export const devVariables = {
  apiEndpoint: 'http://dev.example.com',
}

src/app/environment-variables/production.ts

export const prodVariables = {
  apiEndpoint: 'http://prod.example.com',
}
APIリクエストを共通化する

Angularではproviderとして作るのが一般的ぽいのでそのようにしてみる。

ひな形作成

$ ionic g provider api-service

実行すると src/providers/api-service.ts が生成されるのでここに実装する。
今回は認証用のトークンをローカルストレージに保存しておいて、リクエストのたびにhttpヘッダーにさしこむようにした。

src/providers/api-service.ts

import { Injectable, Inject } from '@angular/core';
import { Http, Headers } from '@angular/http';
import 'rxjs/add/operator/map';

import { Storage } from '@ionic/storage';
import { EnvVariables } from '../app/environment-variables/environment-variables.token';

@Injectable()
export class ApiService {

  constructor(public http: Http, @Inject(EnvVariables) public envVariables,
              private storage: Storage) {
    /* コンストラクタ */
  }

  request(method, action, params) {
    return new Promise((resolve, reject) => {
      this.storage.get('auth.token')
        .then(token => {
          var url = this.envVariables.apiEndpoint + action;
          var http = null;
          var headers = { headers: new Headers({ 'Authorization': 'Token ' + token }) };
          if (method == 'get') {
            http = this.http.get(url, headers)
          } else if (method == 'post') {
            http = this.http.post(url, data, headers)
          }
          if (http !== null) {
            http.subscribe((response) => {
              if (response.status == 200) {
                var result = response.json();
                if (result.status == "success") {
                  resolve(result);
                } else {
                  reject(result.messages);
                }
              } else {
                reject('通信エラーが発生しました');
              }
            },err => {
              reject(err);
            });
          }
        });
    });
  }

  get(url, params) {
    return this.request('get', url, params);
  }

  post(url, data) {
    return this.request('post', url, params);
  }
}

これでコンポーネントから呼び出せる
src/pages/hello.js

import { ApiService } from '../../providers/api-service';

・・・

@Component({
  selector: 'page-hello',
  templateUrl: 'hello.html',
  providers: [ApiService]
})
export class SamplePage {
  constructor(public navCtrl: NavController, private ApiService: ApiService) {
  }

  test() {
    this.ApiService.get('/users/', {})
      .then(data => {
        // success
        console.log(data);
      })
      .catch(messages => {
        // error
        alert(messages);
      });
  }
}

以上です。