仮想サーファーの波乗り

仮想化エンジニアの日常

プログラミング・SNS分析・仮想通貨・自動化などに関してよく書く雑記ブログ

Angular6でアプリ開発②「HTTPでAPIアクセスして仮想通貨一覧ページ表示」

f:id:virtual-surfer:20180603084150p:plain

前回の記事でAngularの基本的な学習方法に関して紹介しましたが、今回からは実際に自分の作りたいアプリケーションを作っていきます。今回から数回に分けて、仮想通貨の各コインの情報を分析するWebアプリケーションを作成していきます。

まず今回はCoinGeckoAPIにHTTPアクセスして、仮想通貨情報を取得してサイト上に表示するところまで実装していきます。


プロジェクトの作成

それでは、アプリケーションを開発していきます。ちなみに、開発時にはIntelliJなど何かしらのIDE(統合開発環境)を使うことをオススメします。コーディング中に補完が効いたり、変数間のジャンプができたりと開発効率を上げることができます。


アプリケーションを作成

$ ng new crypto-news

上のコマンドで「crypto-news」というアプリケーションを作成します。

f:id:virtual-surfer:20180603093519p:plain

アプリを作成したら、上の画像のようなディレクトリ構成になっていると思います。以降は基本的に、src/app配下にファイル追加、src/app配下のファイルを編集していきます。


Component作成

$ cd crypto-news
$ ng generate component currencies

上のコマンドで、アプリケーションのディレクトリに移動して、currenciesという名前のコンポーネントを作成します。これによってcurrenciesディレクトリが作成され、そのディレクトリ配下に「currencies.component.css」「currencies.component.html」「currencies.component.spec.ts」「currencies.component.ts」の4つのファイルが作成されます。

このComponentは後ほど編集していきます。


ルーティングの設定


ルーティングを設定

ルーティングは、pathとComponentを対応づけることで、リンクをクリックしたら特定のページに遷移するように実装できる仕組みです。

$ ng generate module app-routing --flat --module=app

上のコマンドでルーティングを作成します。これによって「app-routing.module.spec.ts」と「app-routing.module.ts」がsrc/app配下にファイル追加されているはずです。「--flat」コマンドは、固有のフォルダの代わりに、src/appに生成したファイルを置き、「--module=app」は、AppModuleのimports配列に、生成したモジュールを登録してくれるコマンドです。

先ほど作成したcurrenciesコンポーネントに対して遷移できるように、ルーティングを設定していきます。app-routing.module.tsファイルに、Routesを設定します。

app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from "@angular/router";
import { CurrenciesComponent } from "./currencies/currencies.component";

const routes: Routes = [
  { path: '', redirectTo: '/currencies', pathMatch: 'full' },
  { path: 'currencies', component: CurrenciesComponent }
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }

「{ path: 'currencies', component: CurrenciesComponent }」の箇所で、currenciesというパスが指定されたらCurrenciesComponentを呼び出すということを設定しています。また、「{ path: '', redirectTo: '/currencies', pathMatch: 'full' }」の記述によって、何もディレクトリを指定されなければcurrenciesにリダイレクトするようにしています。そして、「imports: [ RouterModule.forRoot(routes) ]」の箇所で、ルーターの初期化を行って、ルーターにブラウザのロケーション変化の検知をできるようにしています。

次に、「app.component.html」を編集して、リンクを常に画面上に表示してくれるようにします。

app.component.html

<h1>{{title}}</h1>
<ul>
  <li><a routerLink="/currencies">仮想通貨一覧</a></li>
</ul>
<router-outlet></router-outlet>

ここまででアプリケーションをビルドして起動し、ブラウザを開くとcurrenciesにリダイレクトして、currencies.component.htmlの内容が表示されるようになります。

$ ng serve --open

f:id:virtual-surfer:20180603100755p:plain


HTTPアクセスの実装

現状では画面上に有益な情報が何も表示されていないので、CoinGecko APIにアクセスして、仮想通貨の一覧情報を画面に表示するように実装していきます。


Service作成

$ ng generate service currencies

Serviceには、HTTPアクセスをしてAPIからデータを取得し、そのデータをComponentに渡す処理を記述していきます。上のコマンドで新規作成された「currencies.service.ts」ファイルを以下のように編集していきます。

currencies.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class CurrenciesService {

  API_URL = 'https://api.coingecko.com/api/v3/coins';
  constructor(private http: HttpClient) {}

  request(perPage: string, pageNum: string): Observable<any> {
    return this.http.get(this.API_URL + '?per_page=' + perPage + '&page=' + pageNum);
  }
}

HttpClientモジュールを利用して「https://api.coingecko.com/api/v3/coins」というパスのAPIにHTTPアクセスし、そのレスポンスをObservableで受け取って返しています。このServiceのrequestメソッドをComponentで呼び出し、受け取ったObservableを元にComponentでデータを表示できるように加工していきます。

CoinGecko APIは、コイン一覧情報を取得する際にper_page...1ページにつき何個のコインデータを持たせるか、page...何ページ目のデータを取得するかを指定する必要があるので、その2つを引数で受け取ってAPIアクセスします。

HttpClientモジュールはまだ「app.module.ts」に追加されていないので、追加しておきます。また、先ほど用意したServiceのメソッドをComponentから呼び出せるようにするため、providersにCurrenciesServiceを追加します。

currencies.service.ts

...
import { HttpClientModule } from "@angular/common/http";
import { CurrenciesService } from "./currencies.service";
...
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [
    CurrenciesService
  ],
...

次に、Serviceで用意したメソッドをComponentから呼び出します。「currencies.component.ts」ファイルを以下のように編集します。

currencies.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from "@angular/router";

import { CurrenciesService } from "../currencies.service";

@Component({
  selector: 'app-currencies',
  templateUrl: './currencies.component.html',
  styleUrls: ['./currencies.component.css']
})
export class CurrenciesComponent implements OnInit {

  perPage = '100';
  pageNum = '1';
  currencies: any[];

  constructor(
    private router: Router,
    private currenciesService: CurrenciesService
  ) {}

  ngOnInit() {
    this.onclick(this.pageNum);
  }

  onclick(pageNum: string) {
    this.currenciesService.request(this.perPage, pageNum)
      .subscribe(response => {
          this.currencies = response;
        },
        error => {
          console.log('CoinGeckoへのアクセスに失敗しました。');
        }
      );
  }
}

onclickメソッドでCurrenciesServiceのrequestメソッドを呼び出し、APIアクセスのレスポンスをsubscribeの中で処理します。最初に画面描画された際の初期値を決めておきたいため、「perPage = '100';」「pageNum = '1';」で変数の値を初期化しています。また、ngOnInit()メソッドは最初に呼び出されるので、その処理の中でonclickメソッドを呼び出すことで、画面にアクセスされたらonclickメソッドが呼ばれるようにしています。

ComponentでAPIアクセスのレスポンスをcurrenciesに格納することができたので、「currencies.component.html」でcurrenciesを元に画面にデータを表示していきます。

currencies.component.html

<h2>
  Coins
</h2>
<ul *ngFor="let currency of currencies">
  <li><img src="{{currency.image?.small}}"></li>
  <li>{{currency.name}}({{currency.symbol | uppercase}})</li>
  <li>{{currency.last_updated?.slice(0,10)}} {{currency.last_updated?.slice(11,16)}}</li>
  <li>¥{{currency.market_data.current_price?.jpy | number}}</li>
  <li>¥{{currency.market_data.market_cap?.jpy | number}}</li>
  <li>¥{{currency.market_data.high?.jpy | number}}</li>
  <li>¥{{currency.market_data.low?.jpy | number}}</li>
  <li>{{currency.market_data.price_change_24h?.slice(0,20)}}({{currency.market_data.price_change_percentage_24h?.slice(0,20)}}%)</li>
</ul>

「*ngFor="let currency of currencies"」によって、currenciesをforループで要素がある限り繰り返し処理します。CoinGecko APIのレスポンスは、以下の画像のように各コインの情報が繰り返されている形式なので、その一つ一つに関して処理をしていきます。

f:id:virtual-surfer:20180603105006p:plain

「img src="{{currency.image?.small}}"」では、コインのimageのsmallという要素を取得しています。image要素が存在しない場合もあるので、「image?」で要素が存在すればそのあとの処理をするようにしています。このような処理をしないと、image要素がない場合にsmallを取得しようとしてエラーになって画面の描画ができなくなるので注意です。

以上の実装が終わったら、ブラウザを確認してみましょう。

f:id:virtual-surfer:20180603105507p:plain

上の画像のようにCoinGecko APIで取得したコインデータが一覧で表示されます。画像のデータも提供されているので、いい感じに一覧表示できるのが嬉しいところですね。


まとめ

今回はルーティングの設定、ComponentとServiceの作成、HttpClientを利用したAPIアクセスを実装し、仮想通貨情報の一覧ページを実装していきました。まだまだWebアプリケーションとしては機能に乏しいので徐々に機能と画面を増やしていきます。

次回は、以下のことを実装していきます。

・コイン一覧ページのデザインを見やすくする。
・コイン一覧ページで見れるコイン種類を増やす(ページ指定してCoinGecko APIにアクセスできるように)。


では!


追記(2018/06/05 20:15)

先ほど確認したところ、APIのレスポンスのhighとlowの変数名がhigh_24hとlow_24hに変更されていました。なので、上のコードの該当箇所を新しい値に書き換えないとエラーになってhigh以降の値が表示されません。

CoinGecko APIはデータが豊富なのはありがたいのですが、レスポンスの名前がここ1ヶ月で2度以上変わっている気がします。。。変数名の変更に逐一対応する必要があるので、メンテナンスが大変。。。


では!


ブロックチェーン大学FLOC

仮想通貨・ブロックチェーン業界合同企業説明会