使用Angular调用GitHub的GraphQL API
我会记录一个初学者在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
阿波罗初始化文件
$ npm install apollo-client angular2-apollo graphql-tag --save
使用Apollo可以在Angular中访问GraphQL服务器并获取数据。
在这个示例中,我们将尝试访问GitHub的GraphQL API。
进行GitHub的设置
就个人而言,我在这里遇到了最大的困难。从结论来看,需要仔细阅读这里。→ 访问 GraphQL
首先
你必须已经注册了提前访问计划。
听说了。请遵循指示。
接下来
你需要一个具有正确范围的OAuth令牌。
请阅读“生成OAuth令牌”部分,并按照指示进行操作。
然后使用获得的Token。
把 GitHub Token 包含在项目中
config.secret.default.ts 复制并创建 config.secret.ts 文件。
然后修改其中内容。
export const githubToken = 'your_github_token';
我會按照這樣的方式進行編輯。
当然的事情是,应该注意确保这个文件不会被推送到GitHub仓库中。
编辑app.module.ts
以下是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相关的部分。
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,在ApolloModule中包含生成的ApolloClient的内容,使代码更加清晰。
我稍微明白之前的GitHub令牌是如何在请求头中被包含的。
尝试调用GraphQL API(创建app.service.ts)
阿波罗查询文档
参考Apollo的文件,创建一个Service。因为我现在非常喜欢Redux,所以我会创建一个流程,将API的返回值通过dispatcher发送到Store中。由于apollo.watchQuery的返回值是扩展的Observable,所以熟悉RxJS也是很有好处的。通过使用take(1),确保每次都完成并避免内存泄漏。
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'));
}
}
在组件中接收状态(编辑app.component.ts文件)
由于Redux的存在,组件在调用动作后需要接收状态。
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(); }
}
处理的步骤如下。
-
- 通过调用requestViewer()来调用Service的Action。
通过get state()作为Observable接收更新后的State。
通过{{state | async | json}}使用AsyncPipe接收state的模板。
视图会被更新。
确认Apollo正在缓存数据。
我们来启动应用程序吧。
$ npm start
在浏览器中打开http://localhost:4200/。
当您点击“请求查看者”按钮后,可以确认您的名字是否会显示出来。
不管点击多少次,显示都不会改变,但请使用开发者工具监视网络。你会发现在第二次及以后没有发生HTTP请求。
太酷了!
顺便提一下
this.apollo.watchQuery({ query: CurrentViewerQuery })
將…
this.apollo.watchQuery({ query: CurrentViewerQuery, forceFetch: true })
如果存在缓存,每次都强制获取。有关缓存机制的详细信息,请参考《GraphQL概念可视化》
关于Redux部分
Redux的构建是通过RxJS完成的。源代码在这里。→ src/app/store