2017-01-27 4 views
2

У меня есть API, который возвращает ответы в форматеручки в запросе апи

{ 
    code: 0, // 0 is Ok, all other values is error 
    data: [{...}, {...}, {...}, ...], // data objects 
    message: "" // empty when ok or some error message in other cases 
} 

я пытаюсь создать службу связи для этого API

import { Injectable } from '@angular/core'; 
import { Http, Response } from '@angular/http'; 
import { Observable } from 'rxjs/Observable'; 

interface IApiResponse<T> { 
    code: number; 
    data: Array<T>; 
    message: string; 
} 

@Injectable() 
export class ApiService { 

    constructor( 
    private http: Http 
) { } 

    apiGet<T>(url: string): Observable<Array<T>> { 
    return this.http.get(url) 
      .map((res: Response) => res.json()) 
      //.map((api: IApiResponse<T>) => api.code === 0 ? api.data : Observable.throw(api.message)) 
      .mergeMap((api: IApiResponse<T>) => api.code === 0 ? api.data : Observable.throw(api.message)) 
      .catch(err => Observable.throw(err)); 
    } 

} 

Я хотел бы поднять исключение, когда код поле не равно 0 и возвращать сообщение в части ошибки подписки. Но когда я возвращаю Observable.throw на карте, он возвращается как данные в подписке, а не как ошибка. Когда я пытаюсь использовать mergeMap, исключение возвращает как ошибку в функции подписки как ожидалось, но данные возвращаются для каждого объекта в массиве данных. Это не правильно для меня. Может быть, я должен использовать для этого какую-то другую наблюдаемую функцию?

использование Услуги в компоненте

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

interface ITestItem { 
    id: number; 
    title: string; 
} 

@Component({ 
    selector: 'app-main', 
    templateUrl: './main.component.html', 
    styles: [] 
}) 
export class MainComponent implements OnInit { 

    constructor(
    private apiService: ApiService 
) { } 

    ngOnInit() { 
    this.apiService.apiGet<ITestItem>('/api/test') 
     .subscribe(
     // only data when code = 0 or nothing 
     data => console.log("data section:", data), 
     // handle http errors and message when code != 0 
     error => console.log("error section:", error), 
     () => console.log("api request completed") 
    ); 
    } 

} 

ответ

2

Причина, почему это происходит потому, что mergeMap будет преобразовывать результат к наблюдаемому, если это возможно. Поскольку ваши данные представляют собой массив, он преобразует его в Observable и испускает каждый содержащийся элемент.

Оберните ваши данные с Rx.Observable.of() в .mergeMap, чтобы сохранить его в качестве излучения массива

+0

Да, это работает! Но я не могу понять, почему Observable.throw работает на карте и mergeMap по-разному. – avvensis

+0

Функция карты не передает результаты Observable, поэтому, когда ваша функция карты возвращает Observable.throw, это будет значение, которое оно испускает для функции 'next' для подписки. –

0

Вы довольно близко, на основе RxJS doc. Вы должны выбросить исключение, так как:

Observable.throw(new Error(api.message)); 

Надежда, что помогает

EDIT подробнее

Service, сделать независимо изменения необходимым для вашей потребности.

getTestData(): any { 
    return this.http.get("testUrlShouldThrowError") 
     .map((api: any) => { 
     if (api.code === 0) { 
      return <IApiResponse<Test>>api.data 
     } 
     else { 
      return Observable.throw(new Error("Error!")) 
     } 
     }); 
    } 

Подписка:

this.testService.getTestData().subscribe(
     data => console.log(data.error.message), 
    ) 
+0

.map ((api: IApiResponse ) => api.code === 0? Api.data: Observable.throw (новая ошибка (api.message))) возвращает ErrorObservable в части данных подписки. – avvensis

+0

@avvensis Да, но вы можете получить доступ к своему сообщению об ошибке в вашей подписке 'error => console.log (« error section: », error.error.message)' – 12seconds

+0

Что мне делать? – avvensis