具有不同返回类型的通用数据服务

时间:2018-08-13 14:32:26

标签: angular

我创建了如下所示的通用数据服务:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import { environment } from '../../../environments/environment';
import { Resource } from '../models/resource';

const API_URL = environment.apiUrl;

@Injectable()
export class DataService<T extends Resource> {

  constructor(
    private httpClient: HttpClient,
    private endpoint: string) {}

  public create(item: T): Observable<T> {
    return this.httpClient
      .post<T>(`${API_URL}/${this.endpoint}`, item);
  }

  public update(item: T): Observable<T> {
    return this.httpClient
      .put<T>(`${API_URL}/${this.endpoint}/${item.id}`, item);
  }

  read(id: number): Observable<T> {
    return this.httpClient
      .get(`${API_URL}/${this.endpoint}/${id}`)
      .map(response => response as T);
  }

  list(): Observable<T[]> {
    return this.httpClient
      .get(`${API_URL}/${this.endpoint}`)
      .map(response => response as T[]);
  }

  delete(id: number) {
    return this.httpClient
      .delete(`${API_URL}/${this.endpoint}/${id}`);
  }
}

然后我创建了一个 CategoryService 来扩展此功能:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { DataService } from './data.service';
import { Category } from '../models/category';

@Injectable()
export class CategoryService extends DataService<Category> {

  constructor(httpClient: HttpClient) {
    super(
      httpClient,
      'categories'
    );
  }

}

因此,现在我可以使用该服务的所有CRUD方法了。从那以后,我创建了许多其他服务,每个服务都扩展了DataService。 问题是,我遇到了与返回类型不匹配的API端点。 例如, 端点“ / categories”,我的数据服务希望所有端点返回一个实体,该实体属于类别

import { Resource } from "./resource";

export class Category extends Resource {
    name: string
}

但是,类别API有一个端点,该端点返回问题的列表。该路径是“ / categories / 2 / questions”。 如何使它与我的通用数据服务一起使用? 我想答案是我不能,但是必须有一种解决方法,也许是在每次调用而不是实例化时提供模型类型?

任何帮助将不胜感激。 我希望这是有道理的。

2 个答案:

答案 0 :(得分:1)

听起来这条新路线并不通用。我认为CategoryService应该是实现新方法的类。

export class CategoryService extends DataService<Category> {

  constructor(httpClient: HttpClient) {
    super(
      httpClient,
      'categories'
    );
  }

  getQuestions(id: number): Observable<Question[]> {
    return this.httpClient
      .get<Question[]>(`${API_URL}/${this.endpoint}/${id}/questions`);
  }
}

您可以通过将其访问修饰符更改为endpoint来获得对httpClientprotected的引用

答案 1 :(得分:0)

我决定删除通用服务,而改用通用方法。 因此,数据服务成为(请注意新的query方法:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import { environment } from '../../../environments/environment';

const API_URL = environment.apiUrl;

@Injectable()
export class DataService {

  constructor(
    private httpClient: HttpClient,
    private endpoint: string) {}

  create<T>(item: T): Observable<T> {
    return this.httpClient
      .post<T>(`${API_URL}/${this.endpoint}`, item);
  }

  update<T>(item: T): Observable<T> {
    return this.httpClient
      .put<T>(`${API_URL}/${this.endpoint}/${item.id}`, item);
  }

  read<T>(id: number): Observable<T> {
    return this.httpClient
      .get(`${API_URL}/${this.endpoint}/${id}`)
      .map(response => response as T);
  }

  list<T>(): Observable<T[]> {
    return this.httpClient
      .get(`${API_URL}/${this.endpoint}`)
      .map(response => response as T[]);
  }

  query<T>(path: string): Observable<T[]> {
    return this.httpClient
      .get(`${API_URL}/${this.endpoint}/${path}`)
      .map(response => response as T[]);
  }

  delete(id: number) {
    return this.httpClient
      .delete(`${API_URL}/${this.endpoint}/${id}`);
  }
}

我的类别服务变为:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { DataService } from './data.service';

@Injectable()
export class CategoryService extends DataService {

  constructor(httpClient: HttpClient) {
    super(
      httpClient,
      'categories'
    );
  }

}

要获取我的“类别问题”,我可以这样做:

this.categoryService.query<Question>(`${this.category}/questions`);