我对Angular很陌生。我一直在研究一种服务,该服务从API提取某些数据并返回可观察到的结果。如果服务器中发生内部错误,API可以返回两种类型的JSON响应:自定义数据类型的数组或自定义错误代码和消息。根据这两种可能的响应,我创建了两个接口,例如I1
和I2
。 API返回的两个JSON响应也分别遵循相同的结构。
interface I1 {
responseData: customData[]
}
interface I2 {
errorCode: number,
errorMessage: string
}
对于服务本身,我想编写一个函数,该函数首先获取数据并检查接收到的类型。如果类型为I1
,则它将返回I1
中数组的可观察值,或者如果类型为I2
,则它将在控制台上记录错误并返回错误对象。我已经在服务类中编写了一个函数:
APIResponse: I1 | I2;
getData(): Observable<CustomData[] | I2> {
this.http.get<I1 | I2>('url/to/api').subscribe(res => {
this.APIResponse = res;
});
if('errorCode' in this.APIResponse) {
console.log(this.APIResponse.errorCode);
return of(this.APIResponse);
}
else if('responseData' in APIResponse) {
return of(this.APIResponse.responseData);
}
}
现在,此代码在编译时显示错误,因为this.APIResponse
的类型与该函数为其返回值所期望的类型不同。我可以将函数的返回类型更改为Observable<I1 | I2>
,但是我将无法仅返回数组。我无法以任何方式更改API结构。我尝试将APIResponse发生错误时分配给类型为I2
的中间变量,然后从函数中返回它,但是它不允许我将类型'I1 | I2'
分配给类型'I2'
。
我应该如何从这里开始以获得期望的结果?
答案 0 :(得分:1)
将getData方法更改为:-
getData(): Observable<CustomData[] | I2> {
return this.http.get('url/to/api').pipe(map((res : I1|I2) => {
if('errorCode' in res) {
this.APIResponse = res;
console.log(this.APIResponse.errorCode);
return res;
} else {
this.APIResponse = res;
return res.responseData;
}
}));
}
任何想使用此方法的地方,都可以像这样使用它:-
getData().subscribe((res) => console.log(res));
答案 1 :(得分:0)
我不确定您为什么要订阅服务,但这是反模式的。
如果APIResponse
变量仅在getData()
函数中用于创建新的可观察对象,则不需要它。
要记录响应或执行任何副作用,请使用tap
运算符。
getData(): Observable<CustomData[] | I2> {
return this.http.get<I1 | I2>('url/to/api').pipe(
map(res => {
if ('responseData' in res) {
return res.responseData;
} else if ('errorCode' in res) {
return res;
}
}),
tap(res => {
// Side effects
if ('errorCode' in res) {
console.log(res.errorCode);
}
}),
);
}
如果使用APIResponse
变量并希望为其分配响应,则必须在tap
运算符中进行操作,因为这是副作用。
tap(res => {
// Assign value to APIResponse;
this.APIResponse = res;
})
最后,要从服务器获取数据,请订阅组件中的getData()
可观察流。
this._service.getData().subscribe(data => { // do what you want with data })
如果您的服务使用除2xx
之外的代码发送错误响应,则可以使用catchError
运算符或使用http选项来完全控制请求。