LoginSignup
22
18

More than 5 years have passed since last update.

AngularでGitHubのGraphQL APIを叩く

Last updated at Posted at 2016-10-16

初心者がAngularでGitHubのGraphQLを叩けるようになるまでの手順を記します。Apolloを使います。

今回のGitHubリポジトリ→ ovrmrw/angular-apollo-github-graphql

angular-cliをインストール

$ npm i -g angular-cli

新しいAngularプロジェクトを作成

$ ng new new-project

ng newは通信環境やマシンスペックによってはお風呂に入れるぐらいの時間がかかります。

Apolloをインストール

Apollo Initializationドキュメント

$ npm install apollo-client angular2-apollo graphql-tag --save

Apolloを使うとAngularでGraphQLサーバーを叩いてデータを取得することができます。
今回のサンプルではGitHubのGraphQL APIを叩いてみます。

GitHub側の設定をする

個人的にはここが一番難儀しました。
結論から言うとここをよく読む必要があります。→ Accessing GraphQL

まずは

1) You must be signed up for the Early Access Program.

だそうです。指示に従ってください。
次に

2) You'll need an OAuth token with the right scopes.

だそうです。
Generating an OAuth tokenの項を読んで指示に従ってください。

そして得られたTokenは次で使います。

GitHub Tokenをプロジェクトに含める

config.secret.default.tsをコピーしてconfig.secret.tsを作ります。
そして中身を

config.secret.ts
export const githubToken = 'your_github_token';

のように編集します。

当然のことですがこのファイルはGitHubリポジトリにpushされないよう気を付けなければなりません。

app.module.tsを編集する

これがapp.module.tsの全コードです。

src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import ApolloClient, { createNetworkInterface } from 'apollo-client';
import { ApolloModule } from 'angular2-apollo';

import { AppComponent } from './app.component';
import { AppService } from './app.service';
import { githubToken } from '../../config.secret';
import { StoreModule } from './store';


const networkInterface = createNetworkInterface('https://api.github.com/graphql');
networkInterface.use([{
  applyMiddleware(req, next) {
    if (!req.options.headers) {
      req.options.headers = {};
    }
    req.options.headers['authorization'] = `bearer ${githubToken}`;
    next();
  }
}]);
const client = new ApolloClient({ networkInterface });


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    ApolloModule.withClient(client),
    StoreModule,
  ],
  providers: [AppService],
  bootstrap: [AppComponent]
})
export class AppModule { }

少々ごちゃごちゃしてるのでApolloに関わる部分だけ抜き出してみましょう。

src/app/app.module.ts(抜粋)
import ApolloClient, { createNetworkInterface } from 'apollo-client';
import { ApolloModule } from 'angular2-apollo';

import { githubToken } from '../../config.secret';


const networkInterface = createNetworkInterface('https://api.github.com/graphql');
networkInterface.use([{
  applyMiddleware(req, next) {
    if (!req.options.headers) {
      req.options.headers = {};
    }
    req.options.headers['authorization'] = `bearer ${githubToken}`;
    next();
  }
}]);
const client = new ApolloClient({ networkInterface });


@NgModule({
  imports: [ApolloModule.withClient(client)],  
})
export class AppModule { }

大分すっきりしました。
networkInterfaceというのを作ってApolloClientを生成してApolloModuleに含めるという内容です。
先程のGitHub Tokenはリクエストのヘッダーに含めているのだということがなんとなくわかりますね。

GraphQL APIを叩いてみる (app.service.tsを作る)

Apollo Queriesドキュメント

Apolloのドキュメントを参考にしつつServiceを作ります。
僕は今のところRedux大好きっ子なのでAPIの戻り値をdispatcherでStoreに送るという流れを作ります。
apollo.watchQueryの戻り値は拡張したObservableなのでRxJSにも慣れておくと良いでしょう。take(1)を挟むことで毎回completeしてメモリリークしないようにしています。

src/app/app.service.ts
import { Injectable } from '@angular/core';
import { Angular2Apollo } from 'angular2-apollo';
import gql from 'graphql-tag';

import { environment } from '../environments/environment';
import { Dispatcher, Action, RequestViewerAction, ViewerState } from './store';


const CurrentViewerQuery = gql`
  query {
    viewer {
      name
      login
    }
  }
`;


@Injectable()
export class AppService {
  constructor(
    private dispatcher$: Dispatcher<Action>,
    private apollo: Angular2Apollo,
  ) { }


  requestViewer(): void {
    console.time('requestViewer');
    this.apollo
      .watchQuery({ query: CurrentViewerQuery })
      .take(1)
      .subscribe(result => {
        if (!environment.production) {
          console.log('result:', result);
        }
        const viewer = result.data.viewer as ViewerState;
        this.dispatcher$.next(new RequestViewerAction(viewer));
      }, err => console.error(err), () => console.timeEnd('requestViewer'));
  }

}

ComponentでStateを受ける (app.component.tsを編集する)

ReduxですのでComponentはActionを呼んだ後Stateを受ける必要があります。

src/app/app.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Observable } from 'rxjs/Rx';

import { AppService } from './app.service';
import { Store, AppState } from './store';


@Component({
  selector: 'app-root',
  template: `
    <h1>{{title}}</h1>
    <pre>{{state | async | json}}</pre>
    <div>
      <button (click)="requestViewer()">Request Viewer</button>
    </div>
  `,
  styleUrls: ['./app.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  title = 'app works!';

  constructor(
    private service: AppService,
    private store: Store,
  ) { }


  requestViewer(): void {
    this.service.requestViewer();
  }

  get state(): Observable<AppState> { return this.store.getState(); }

}

処理の流れはこう。

  1. requestViewer()でServiceのActionを呼ぶ。
  2. get state()で更新されたStateをObservableとして受ける。
  3. templateの{{state | async | json}}stateをAsyncPipeで受ける。
  4. Viewが更新される。

Apolloがデータをキャッシュしていることを確認する

アプリを起動してみましょう。

$ npm start

http://localhost:4200/をブラウザで開きます。

Request Viewerボタンをクリックすると自分の名前が表示されることが確認できるかと思います。

さらに何回もクリックしても表示は変わりませんが、デベロッパーツールでNetworkを監視してみてください。2回目以降はHTTPリクエストが発生していないことがわかります。

So Cool!!

ちなみに

src/app/app.service.ts
this.apollo.watchQuery({ query: CurrentViewerQuery })

src/app/app.service.ts
this.apollo.watchQuery({ query: CurrentViewerQuery, forceFetch: true })

とするとキャッシュしていても毎回強制的にfetchします。キャッシュの仕組みに関してはGraphQL Concepts Visualizedが詳しいです。

Redux部分について

ReduxはRxJSで構築しています。ソースコードはこちら。→ src/app/store

22
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
18