Разбор необычного http ответа с Angular, Rx JS в шаблоне Facade - PullRequest
1 голос
/ 18 февраля 2020

У меня есть Back-End API, который возвращает данные в следующей структуре:

{
    "code": 200,
    "message": "Success",
    "data": // Can basically be anything.. object, array, string, etc...
}

Дело в том, что я действительно озадачен тем, как все это должно работать с такой вложенной полезной нагрузкой.

Хотелось бы получить еще немного советов о том, как реализовать эту мерзость в моем шаблоне проектирования и как сделать это правильно.

В моем арсенале есть следующее оружие:

APIResponse - Модель

export default interface APIResponse {
    code: number;
    message: string;
    data?: any;
}

NetworkService - Сервис

@Injectable({ providedIn: 'root' })
export class NetworkService {
    constructor(private http: HttpClient) { }

    private _formatErrors(error: any) {
        return throwError(error);
    }

    get(environment: string, path: string, params: HttpParams = new HttpParams()): Observable<APIResponse> {
        return this.http.get<APIResponse>(`${environment}${path}`, { params }).pipe(catchError(this._formatErrors));
    }
}

PostsAPI

Я застрял именно здесь. Как преобразовать атрибут APIResponse data в Post[] Наблюдаемый?

@Injectable({ providedIn: 'root' })
export class PostsAPI {
    // Lifecycle
    constructor(private _network: NetworkService) { }

    // API Methods
    getAllPosts(page: number = 1, limit: number = 10): Observable<Post[]> {
        return this._network.get(GlobalAPI.baseURL, `${GlobalAPI.endpoints.posts.base}?page=${page}&limit=${limit}`); // Obviously I have a type mismatch here and I'm doing it all wrong.
    }
}

PostsFacade

@Injectable({ providedIn: 'root' })
export class PostsFacade {
    posts$: Observable<Post[]>;

    // Lifecycle
    constructor(private _postsAPI: PostsAPI) {
        this._postsAPI.getAllPosts().subscribe(response => this.posts$ = response.data.posts); // Obviously I have a type mismatch here and I'm doing it all wrong.
    }
}

HomeComponent - страница, на которой отображаются сообщения

@Component({
    selector: 'app-home',
    templateUrl: './home.component.html',
    styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
    posts$ = this._postsFacade.posts$;

    // Lifecycle
    constructor(private _postsFacade: PostsFacade) { }
    ngOnInit() {
        console.log(this.posts$); // Returns undefined
    }
}

Большое спасибо!

Ответы [ 2 ]

1 голос
/ 18 февраля 2020

Внутри вашего PostsFacade вы не должны подписываться на наблюдаемое, потому что тогда сообщения $ не будут иметь тип Observable. PostsFacade:

@Injectable({ providedIn: 'root' })
export class PostsFacade {
    posts$: Observable<Post[]>;

    // Lifecycle
    constructor(private _postsAPI: PostsAPI) {
        this.posts$ = this._postsAPI.getAllPosts()
    }
}

Теперь для преобразования атрибута данных APIResponses в Post [] используйте rx js оператор карты следующим образом: PostsApi:

@Injectable({ providedIn: 'root' })
export class PostsAPI {
    // Lifecycle
    constructor(private _network: NetworkService) { }

    // API Methods
    getAllPosts(page: number = 1, limit: number = 10): Observable<Post[]> {
        return this._network.get(GlobalAPI.baseURL, `${GlobalAPI.endpoints.posts.base}?page=${page}&limit=${limit}`).pipe(map(apiResponse => responseToPosts(apiResponse)));
    }
}

С responseToPosts(apiResponse:APIResponse):Post[] функция, которая преобразует ваш apiResponse в сообщение []

1 голос
/ 18 февраля 2020

Лучше всего развернуть ApiResponse и обработать ошибки (ведение журнала, отображение всплывающего окна для пользователя и т. Д. c.) В пределах NetworkService. Каждая служба бизнес-объекта может вызывать сетевую службу и получать выгоду от этой логики c.

. И, как упоминается в комментарии, this.posts$ в вашем PostsFacade должно быть наблюдаемым (или вы указываете своим '$ '), так что не подписывайтесь там. Это позволит вам использовать канал asyn c в шаблоне компонента для автоматической подписки / отмены подписки. В противном случае ...

posts: Post[];

ngOnInit() {
  this._postsApi.getAllPosts().subscribe(posts => this.posts = posts);
}
...