【Angular入門(8)】Rest APIをコールしてみる

はじめに

最近、Ajax通信でAPIをコールしてJSON形式で取得したデータで動的に画面を差分更新するようなSPAの開発が流行っています。

今回は、AngularでRest APIをコールしてJSON形式のデータを取得し、データをリスト表示するサンプルプログラム作成を行います。

ついでに、コールされる側のAPIもSpring Bootで作成してみましょう。

 

今回やりたいことを絵にすると、こんな感じ

 

 

 環境

  • OS:OS X 10.11 El Capitan
  • STS:3.8.4.RELEASE
  • node:v8.1.0
  • Angular CLI:1.1.1
  • Visual Studio Code:1.13

 

前提

以下が完了している前提で説明します。

【Angular入門(6)】コンポーネントを作ってみる

 

【Spring Boot入門(4)】Rest API(GET)を作ってみる

 

 

サンプルプログラム作成手順

サンプルプログラムは以下の手順で行います。

  1. RestAPIの修正(JSONP対応)
  2. AngularのRestAPIコールサービス追加
  3. ローカルPCでAPサーバ、Webサーバ起動

 

1.RestAPIの修正(JSONP対応)

まずはバックエンドの作成から行います。

事前に作成したRest APIをJSONPでコールできるように、JsonpAdvice.javaを追加します。

src/main/java/com/example/RestApiApplication.java
package com.example;

import java.io.IOException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
    public JsonpAdvice() {
        super("callback");
    }
    @Bean
    public MappingJackson2HttpMessageConverter MappingJackson2HttpMessageConverter(ApplicationContext ctx) {
        ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().applicationContext(ctx).build();
        return new MappingJackson2HttpMessageConverter(mapper) {
            @Override
            protected void writePrefix(JsonGenerator generator, Object obj) throws IOException {
                if (!(obj instanceof MappingJacksonValue))
                    return;
                String funcName = ((MappingJacksonValue) obj).getJsonpFunction();
                if (funcName != null)
                    generator.writeRaw(funcName + "(");
            }
        };
    }
}

最終的に出来上がるRestAPIのプロジェクト構成は以下のようになります。

MEMO

■クロスドメイン制約

XMLHttpRequest(ブラウザ上でサーバとHTTP通信をするためのAPI)では別ドメインにリクエストできない制約。

ブラウザを操作している人が意図しないところで勝手にAjax通信で別サービスに個人情報を登録される。。。みたいなことにならないための制約。

 

■JSONP

クロスドメインのAPIからデータを取得するしくみ。scriptタグのsrc属性ではクロスドメインのURLを指定してデータを取得することができる。これをJSONPでは利用する。

JSONPを実現するためにRest API側の対応も必要となる。

 

以上でRestAPIの修正は完了です。

 

2.AngularのRestAPIコールサービス追加

次はAngularからRestAPIをコールするサービスを追加します。

やることは以下。

  • item.service.tsの作成
  • app.module.tsの修正
  • dashboard.component.tsの修正

 

itemService.tsの作成

src/app/services/item.service.ts
import { Injectable }    from '@angular/core';
import { Headers, Http, Jsonp, RequestOptionsArgs, RequestOptions, URLSearchParams} from '@angular/http';
import {Observable} from  "rxjs/Observable";
import "rxjs/add/operator/map";

import { Item } from '../item';

@Injectable()
export class ItemService {

  //RestAPIのURL
  private itemsUrl = 'http://localhost:8080/api/items';
  //JSONPコールバック関数名(Angular固有値)
  CALLBACK = 'JSONP_CALLBACK';
  

  //コンストラクタで利用するモジュールをインスタンス化
  constructor(private http: Http, private jsonp: Jsonp) { }


  //商品一覧取得
  getItems(): Observable<Item[]> {
    //リクエストパラメータセット
    let option : RequestOptions;
    option = this.setHttpGetParam(this.itemsUrl);

    //レスポンス返却
    return this.jsonp.request(this.itemsUrl, option)
      .map((response) => {
        let content;
        let obj = response.json();
        content = {
          error: null,
          data: obj
        };
        console.dir(content);
        return content;

      });
               
  }


  //Http(Get)通信のリクエストパラメータをセットする
  private setHttpGetParam(url: string): RequestOptions {
    let param = new URLSearchParams();
    param.set("callback", this.CALLBACK);
    let options: RequestOptionsArgs = {
      method: "get",
      url: url,
      search: param
    };
    return new RequestOptions(options);
  }

}

 

2.app.module.tsの修正

src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
//RestAPIコールに利用するモジュール追加
import { HttpModule,JsonpModule} from '@angular/http';

import { DashboardComponent } from './dashboard.component';
import { AppComponent } from './app.component';

//商品情報取得用serviceを追加
import {ItemService} from './services/item.service';

@NgModule({
  declarations: [
    AppComponent,
    //DashboardComponentを読み込めるように追加
    DashboardComponent
  ],
  imports: [
    BrowserModule,
    //RestAPIコールに利用するモジュール追加
    HttpModule,
    JsonpModule
  ],
  providers: [
    //商品情報取得用serviceをDIできるように追加
    ItemService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

3.dashboard.component.tsの修正

src/app/dashboard.component.ts
import {Component, OnInit} from "@angular/core";
import {Item} from "./item";
import {ItemService} from "./services/item.service";

@Component({
    selector: "my-dashboard",
    template: `
        <ul>
            <li *ngFor = "let item of itemList">
                {{item.name}}:{{item.price}}円
            </li>
        </ul>
    `,

})

export class DashboardComponent implements OnInit{

    //コンポーネント生成時の処理
    constructor(private itemService: ItemService){}

    //商品リスト
    itemList : Item[];

    //画面初期表示イベント処理
    ngOnInit(): void {
        this.itemService.getItems().subscribe(
            result => this.setItems(result),
            error => alert('通信エラー' + error)
        );
    }

    //Web APIから取得したデータを商品リストにセットする
    setItems(result): void {
        if(result.error) {
            alert('Web APIエラー' + result.message);
        }

        this.itemList = result.data;
    }
}
MEMO

ngOnInit()で画面初期表示時にitemService.getItems()をコールしました。

APIコール時にはJSONPを利用し、

取得したデータはitemListにセットしてAngularが画面を差分更新してくれるって感じです。

最終的に出来上がるAngularプロジェクトの構成は以下のようになります。

以上でRestAPIをコールするサービス追加は完了です。

 

3.ローカルPCでAPサーバ、Webサーバ起動

APサーバ起動

STSを開き、パッケージ・エクスプローラーでsrc/main/java/com/example/RestApiApplication.javaを右クリック>実行>Spring Boot アプリケーションでAPサーバを起動します。

 

Webサーバ起動

VS Codeを開き、「Shift」+「Control」+「@」でターミナルを開きます。

カレントディレクトリをプロジェクト内に移し、以下コマンドでWebサーバを起動します。

command
> ng serve
Google Chromeで「http://localhost:4200」にアクセスします。

以上で、AngularでRestAPIをコールするサンプルプログラム作成は完了です。

 

 

おわりに

今回はAngularでRest APIをコールするサンプルプログラムと、コールされる側のRestAPIをBoot Strapで作成しました。

クロスドメイン制約を回避するためには、JSONP対応をサーバ側で行い、コールバック関数でデータを受け取って・・・でしたね。

今回はGETメソッドのHTTP通信だったのでJSONPが利用できましたが、

POSTやPUTメソッドの場合、サーバ側でクロスドメインでのアクセスは〇〇ドメインからのみ許可みたいな設定が必要になります。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください