在Angular API服务中安全处理深度嵌套和复杂的json对象

时间:2019-07-18 20:07:47

标签: angular typescript nested rxjs

我正在为洗车开发API服务,该服务检索大型的复杂json对象(洗车对象)。这个对象的几乎每个属性都是另一个对象,它包含简单数据类型和必须实例化的其他自定义对象 。我已经看到了很多具有1或2级属性的对象的实例,这些对象利用RxJs map函数,但是对于像这样的深层嵌套对象,这似乎并不可行。

Carwash.model.ts概述

export class Carwash {
public name: string;
public type: CARWASH_TYPE;
public rating: Rating;
public address: Address;
private _coordinates: CarwashCoordinates;
public promotions: Promotion[];
public silverPackage: Package;
public goldPackage: Package;
public platinumPackage: Package;
public exteriorPackage: Package;
public interiorPackage: Package;
public completePackage: Package;
public storeHours: StoreHours;
}

ApiService.ts

public static carwashUrl = 'http://localhost:4200/assets/data/carwash.json';
private static carwashObject: Carwash;
public name: string;
public type: CARWASH_TYPE;
public ratings: Rating[];
public address: Address;
private _coordinates: CarwashCoordinates;
public promotions: Promotion[];
public silverPackage: Package;
public goldPackage: Package;
public platinumPackage: Package;
public exteriorPackage: Package;
public interiorPackage: Package;
public completePackage: Package;
public storeHours: StoreHours;
constructor(private http: HttpClient) {
}

public getCarwash() {
    console.log('getCarwash called');
    if (!CarwashService.carwashObject) {
        this.fetchCarwash().subscribe(
            (carwash => CarwashService.carwashObject = carwash)
        );
    } else {
        console.log('Carwash already fetched.');
    }
}

private fetchCarwash(): Observable<Carwash> {
    return this.http.get<any>(CarwashService.carwashUrl).pipe(
        map(res => {
            const carwashData = res.json();
            this.name = carwashData.name; // Top level stuff is np
            this.type = carwashData.type; // Top level stuff is np
            for (const rating of carwashData.ratings) {
                this.ratings.push(new Rating(rating.customerName,
                    rating.score,
                    rating.review,
                    rating.date)); // Top level stuff is np
            }
            this.address = // When it comes to instantiating custom objects I'm not sure how to go about it in an elegant way.
            return new Carwash(this.name, this.type, etc...)
        })
    )
}

映射是实现此目标的唯一方法吗?我应该实现帮助函数来清理get调用吗?我不知道。

注意:不需要自定义对象结构。您需要知道的是它们由基本数据类型以及其他自定义对象组成。

2 个答案:

答案 0 :(得分:1)

您可以执行以下操作:

http.get<CarWash>(this.carwashApiUrl).subscribe((carwash: CarWash) => console.log(carwash));

...当然,您的CarWash类需要定义所有可用的复杂属性。对于这种定义,您还可以使用Swagger编辑器之类的生成器将它们从api的类定义中删除(如果有的话)。 之后,您仍然可以将CarWashDto映射到CarWash对象,但是在UI中需要它。

答案 1 :(得分:1)

如果您需要实际的对象实例,而不仅仅是具有适当类型的形状的对象图,则可以使用如下代码:

使用Object.assign:

  productsClassInstance$ = this.http.get<ProductClass>(this.productsUrl)
    .pipe(
      map(product => Object.assign(new ProductClass(), {
        ...product,
        suppliers: (product.suppliers ? product.suppliers.map(supplier => Object.assign(new SupplierClass(), {
          ...supplier
        })) : [])
      }))
    );

这使用map运算符将响应映射到对象图。它利用Object.assign创建该类的新实例,并利用散布运算符(...)将数据复制到该新实例中。

对于每个“子”对象或对象数组,您可以使用类似的代码。

[已更新为多个级别的对象]

或使用构造函数

productsClassInstanceMultipleLevels2$ = this.http.get<ProductClass[]>(this.productsUrl)
.pipe(
  map(products => products.map(product => 
    new ProductClass(
      product.id, 
      product.productName,
      (product.suppliers ? product.suppliers.map(supplier => new SupplierClass(
        supplier.id,
        supplier.name
      )) : []) ))
  )
);

[再次更新为使用构造函数代替Object.assign]