我正在构建一个 Angular2 应用程序,其中一个组件需要进行多个 API 调用,这些调用依赖于之前的组件。
我目前有一项服务可以调用 API 来获取电视节目列表。对于每个节目,然后我需要多次调用不同的 API 来遍历结构以确定该节目是否存在于 Plex 服务器上。
API 文档是 here
对于每个节目,我需要进行以下调用并获取正确的数据以确定它是否存在:(假设我们有变量 <TVShow>, <Season>, <Episode>
)
http://baseURL/library/sections/?X-Plex-Token=xyz
会告诉我:
title="TV Shows" key="2"
http://baseURL/library/sections/2/all?X-Plex-Token=xyz&title=<TVShow>
会告诉我:key="/library/metadata/2622/children"
http://baseURL/library/metadata/2622/children?X-Plex-Token=xyz
会告诉我:index="<Season>" key="/library/metadata/14365/children"
http://baseURL/library/metadata/14365/children?X-Plex-Token=xyz
会告诉我:index="<Episode>"
这意味着我所拥有的情节存在。
响应是在 json 中,我已经删除了很多多余的文本。在每个阶段,我都需要检查是否存在正确的字段 ( <TVShow>, <Season>, <Episode>
),以便它们可以用于下一次调用。如果没有,我需要返回该节目不存在。如果是这样,我可能会想要返回该节目的 ID。
我看过很多例子,包括 promise、async 和 flatmap,但我不确定如何根据我看到的其他例子来解决这个问题。
- How to chain Http calls in Angular2
- Angular 2.0 And Http
- Angular 2 - What to do when an Http request depends on result of another Http request
- Angular 2 chained Http Get Requests with Iterable Array
- nodejs async: multiple dependant HTTP API calls
- How to gather the result of Web APIs on nodeJS with 'request' and 'async'
这是我用来获取节目列表的内容。 (显示.service.ts)
export class ShowsHttpService {
getShows(): Observable<Show[]> {
let shows$ = this._http
.get(this._showHistoryUrl)
.map(mapShows)
.catch(this.handleError);
return shows$;
}
}
function mapShows(response:Response): Show[] {
return response.json().data.map(toShow);
}
function toShow(r:any): Show {
let show = <Show>({
episode: r.episode,
show_name: r.show_name,
season: r.season,
available : false, // I need to fill in this variable if the show is available when querying the Plex API mentioned above.
});
// My best guess is here would be the right spot to call the Plex API as we are dealing with a single show at a time at this point, but I cannot see how.
return show;
}
这里是组件的相关代码(shows.component.ts)
public getShows():any {
this._ShowsHttpService
.getShows()
.subscribe(w => this.shows = w);
console.log(this.shows);
}
奖励积分
下面是明显的下一个有趣但不是必需的问题:
- 第一个 API 查询比等待所有其他查询发生要快得多(显示 4 个查询 * ~10)。可以返回初始列表,然后使用
available
更新吗?准备就绪时的状态。 - 获得
key="2"
的第一个 Plex 调用只需执行一次。它可以进行硬编码,但是否可以执行一次并记住? - 有没有办法减少 API 调用的次数?我可以看到我可以删除显示过滤器,并在客户端上搜索结果,但这也不是很理想。
- 每个节目的 4 次调用必须按顺序完成,但可以并行查询每个节目以提高速度。这可以实现吗?
如有任何想法,我们将不胜感激!
最佳答案
不确定我是否完全理解你的问题,但这是我所做的:
我进行第一个 http 调用,然后当订阅触发时,它调用 completeLogin。然后我可以用它自己的完整功能触发另一个 http 调用并重复链。
这是组件代码。用户已填写登录信息并按下登录:
onSubmit() {
console.log(' in on submit');
this.localUser.email = this.loginForm.controls["email"].value;
this.localUser.password = this.loginForm.controls["password"].value;
this.loginMessage = "";
this.checkUserValidation();
}
checkUserValidation() {
this.loginService.getLoggedIn()
.subscribe(loggedIn => {
console.log("in logged in user validation")
if(loggedIn.error != null || loggedIn.error != undefined || loggedIn.error != "") {
this.loginMessage = loggedIn.error;
}
});
this.loginService.validateUser(this.localUser);
}
这会调用登录服务的 ValidateUser 方法
validateUser(localUser: LocalUser) {
this.errorMessage = "";
this.email.email = localUser.email;
var parm = "validate~~~" + localUser.email + "/"
var creds = JSON.stringify(this.email);
var headers = new Headers();
headers.append("content-type", this.constants.jsonContentType);
console.log("making call to validate");
this.http.post(this.constants.taskLocalUrl + parm, { headers: headers })
.map((response: Response) => {
console.log("json = " + response.json());
var res = response.json();
var result = <AdminResponseObject>response.json();
console.log(" result: " + result);
return result;
})
.subscribe(
aro => {
this.aro = aro
},
error => {
console.log("in error");
var errorObject = JSON.parse(error._body);
this.errorMessage = errorObject.error_description;
console.log(this.errorMessage);
},
() => this.completeValidateUser(localUser));
console.log("done with post");
}
completeValidateUser(localUser: LocalUser) {
if (this.aro != undefined) {
if (this.aro.errorMessage != null && this.aro.errorMessage != "") {
console.log("aro err " + this.aro.errorMessage);
this.setLoggedIn({ email: localUser.email, password: localUser.password, error: this.aro.errorMessage });
} else {
console.log("log in user");
this.loginUser(localUser);
}
} else {
this.router.navigate(['/verify']);
}
在我的登录服务中,我调用了授权服务,它返回一个可观察到的 token 。
loginUser(localUser: LocalUser) {
this.auth.loginUser(localUser)
.subscribe(
token => {
console.log('token = ' + token)
this.token = token
},
error => {
var errorObject = JSON.parse(error._body);
this.errorMessage = errorObject.error_description;
console.log(this.errorMessage);
this.setLoggedIn({ email: "", password: "", error: this.errorMessage });
},
() => this.completeLogin(localUser));
}
在授权服务中:
loginUser(localUser: LocalUser): Observable<Token> {
var email = localUser.email;
var password = localUser.password;
var headers = new Headers();
headers.append("content-type", this.constants.formEncodedContentType);
var creds:string = this.constants.grantString + email + this.constants.passwordString + password;
return this.http.post(this.constants.tokenLocalUrl, creds, { headers: headers })
.map(res => res.json())
}
这段代码的重点是,首先调用登录服务的validateUser方法,响应后,根据返回信息,如果有效,我调用登录服务的loginUser方法。只要你需要,这条链就可以继续下去。您可以设置类级变量来保存链的每个方法中所需的信息,以决定下一步要做什么。
另请注意,您可以在服务中订阅返回并在那里进行处理,它不必返回到组件。
好的,开始了:
public getShows():any {
this._ShowsHttpService
.getShows()
.subscribe(
w => this.shows = w,
error => this.errorMessage = error,
() => this.completeGetShows());
}
completeGetShow() {
//any logic here to deal with previous get;
this.http.get#2()
.subscribe(
w => this.??? = w),
error => this.error = error,
() => this.completeGet#2);
}
completeGet#2() {
//any logic here to deal with previous get;
this.http.get#3()
.subscribe(
w => this.??? = w),
error => this.error = error,
() => this.completeGet#3);
}
completeGet#3() {
//any logic here to deal with previous get;
//another http: call like above to infinity....
}
关于api - Angular2 - 多个依赖顺序 http api 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39053965/