SOAP ベースのウェブサービスの利用

2017年現在、Ionic Native の HTTP プラグインによる POST リクエストでは、 リクエストボディには JSON を入れることを想定してあります。これだと、SOAP ベース、 つまり、XML の SOAP メッセージをポストするのは不適切です。

Web サービスという言葉も古くなってきた感がありますね。「Web Service のトレンド

このため XML のポストには他の方法が必要です。

ここでは SOAP ベースの Web サービスを利用するために、 Angular の Http クラスを用いて、SOAP メッセージを POST する方法を示します。

Http クラスを利用するために、まずはルートモジュールに HttpModule を取り込みます

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { HttpModule } from '@angular/http';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    HttpModule,
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

Http クラスを利用するページの例は次の通りです。

ここでは、具体例として緯度経度の情報からカリフォルニア州の税率を取得するサービスを呼び出しています。

import { Component, OnInit } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Geolocation, GeolocationOptions } from '@ionic-native/geolocation';
import { HTTP } from '@ionic-native/http';
import { Http, RequestOptionsArgs, Headers } from '@angular/http';

import 'rxjs/add/operator/toPromise';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
})
export class HomePage implements OnInit {

  ...
  tax: string;

  constructor(
    private http: Http,
    public navCtrl: NavController) {}

    ...

    getRate(lat: number, lng: number) {

      let headers = new Headers();
      headers.set('Content-Type', 'text/xml; charset=utf-8');
      headers.set('SOAPAction','http://services.gis.boe.ca.gov/api/taxrates/CATaxRateAPI/GetRate');

      let options : RequestOptionsArgs = {
        headers: headers
      };

      return this.http.post(
            'http://services.gis.boe.ca.gov/api/taxrates/Rates.svc',
            `<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
              <s:Body>
                <GetRate xmlns="http://services.gis.boe.ca.gov/api/taxrates">
                  <request xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                    <City i:nil="true"/>
                    <Latitude>${lat}</Latitude>
                    <Longitude>${lng}</Longitude>
                    <State i:nil="true"/>
                    <StreetAddress i:nil="true"/>
                    <ZipCode i:nil="true"/>
                    <ZipCodePlusFour i:nil="true"/>
                  </request>
                </GetRate>
              </s:Body>
            </s:Envelope>`,
            options
        )
        .toPromise()
        .then((resp)=>{
          let xml = resp.text();
          let xmlDoc = (new DOMParser()).parseFromString(xml, "text/xml");
          let rate = parseFloat(
            xmlDoc.getElementsByTagName("Rate")[0].childNodes[0].nodeValue
          ) * 100;
          this.tax = `${rate}%`;
        })
        .catch((err)=>{
          this.tax = err;
        });

    }
    ...

XML のエンベロープはウェブサービス毎に違うので、どのような Envelope を作るかはそれぞれのマニュアルを参考にしてください。 あるいは、成功する呼出しをキャプチャして、それと同様の HTTP ボディ (XML) を作成します。

ここでのポイントはまず、HTTP ヘッダを書き換える所です。

@angular/http で Headers が定義されていますので、set メソッドで Content-Type と SOAPAction を追加します。

HTTP ヘッダの情報を、同じく @angular/http で定義される RequestOptionsArgs にセットします。

このオプション情報を Http オブジェクトの post メソッドに渡すことで、HTTP ヘッダの書き換えが可能になります。

レスポンスは @angular/http の Response として返りますので、toPromise して、then で受けとります。

Response は static_response.d.ts 辺りをみればわかります。

Response は Body から派生するので text() メソッドでレスポンスとなる XML が取得できます。

この XML を DOM パーサーで XML オブジェクトに変換し、必要な情報を抜き出せば OK です。