如何用ngrx/Data实现带路径参数的API调用?
用NgRx Data适配路径参数API的实现方案
你的需求完全可以实现,既可以通过重写EntityCollectionServiceBase的方法,也可以通过自定义HttpUrlGenerator来统一处理URL生成逻辑,后者是更推荐的通用方案,以下是具体实现步骤:
方案一:自定义HttpUrlGenerator(推荐)
NgRx Data默认通过DefaultHttpUrlGenerator生成请求URL,我们可以继承这个类并重写URL生成逻辑,适配路径参数的API格式。
1. 创建自定义URL生成器
import { DefaultHttpUrlGenerator, HttpResourceUrls, QueryParams } from '@ngrx/data'; import { Pluralizer } from '@ngrx/data'; export class CustomHttpUrlGenerator extends DefaultHttpUrlGenerator { constructor(pluralizer: Pluralizer) { super(pluralizer); } override getResourceUrl( entityName: string, operation: string, resourceUrls: HttpResourceUrls, params: QueryParams | undefined ): string { let url = super.getResourceUrl(entityName, operation, resourceUrls, params); // 针对Entity实体处理路径参数 if (entityName === 'Entity') { switch (operation) { case 'getAll': // 从请求参数中获取CategoryIdentifier,替换为路径参数 const categoryId = params?.['CategoryIdentifier']; if (categoryId) { url = `/api/v1/Entity/${categoryId}`; // 移除查询参数,避免API接收无效参数 delete params?.['CategoryIdentifier']; } break; case 'getById': case 'delete': // 处理需要双路径参数的请求 const catId = params?.['CategoryIdentifier']; const entityId = params?.['id']; if (catId && entityId) { url = `/api/v1/Entity/${catId}/${entityId}`; delete params?.['CategoryIdentifier']; delete params?.['id']; } break; // POST/PUT使用默认根路径,无需修改 case 'add': case 'update': url = `/api/v1/Entity`; break; } } return url; } }
2. 替换默认的URL生成器
在AppModule中提供自定义生成器,覆盖NgRx Data的默认实现:
import { NgModule } from '@angular/core'; import { HTTP_URL_GENERATOR, Pluralizer } from '@ngrx/data'; import { CustomHttpUrlGenerator } from './custom-http-url-generator'; @NgModule({ providers: [ { provide: HTTP_URL_GENERATOR, useFactory: (pluralizer: Pluralizer) => new CustomHttpUrlGenerator(pluralizer), deps: [Pluralizer] } ] }) export class AppModule {}
3. 使用EntityCollectionService发起请求
调用NgRx Data的标准方法时,通过params传递路径参数:
// 获取指定分类下的所有实体 this.entityService.getAll({ params: { CategoryIdentifier: 'cat_001' } }); // 获取单个实体 this.entityService.getById('entity_1001', { params: { CategoryIdentifier: 'cat_001' } }); // 删除实体 this.entityService.delete('entity_1001', { params: { CategoryIdentifier: 'cat_001' } }); // 新增实体(直接用默认方法) this.entityService.add(newEntity); // 更新实体(直接用默认方法) this.entityService.update(updatedEntity);
方案二:重写EntityCollectionServiceBase方法
如果仅针对单个实体做特殊处理,可以创建自定义的EntityService,继承EntityCollectionServiceBase并重写对应方法,手动构造请求URL和处理缓存:
import { Injectable } from '@angular/core'; import { EntityCollectionServiceBase, EntityCollectionServiceElementsFactory } from '@ngrx/data'; import { HttpClient } from '@angular/common/http'; import { tap } from 'rxjs/operators'; import { Entity } from './entity.model'; @Injectable() export class EntityService extends EntityCollectionServiceBase<Entity> { constructor( serviceElementsFactory: EntityCollectionServiceElementsFactory, private http: HttpClient ) { super('Entity', serviceElementsFactory); } // 获取指定分类下的所有实体 getAllByCategory(categoryIdentifier: string) { const url = `/api/v1/Entity/${categoryIdentifier}`; return this.http.get<Entity[]>(url).pipe( tap(entities => this.addManyToCache(entities)) // 更新NgRx缓存 ); } // 获取单个实体 getEntity(categoryIdentifier: string, entityIdentifier: string) { const url = `/api/v1/Entity/${categoryIdentifier}/${entityIdentifier}`; return this.http.get<Entity>(url).pipe( tap(entity => this.addOneToCache(entity)) ); } // 删除实体 deleteEntity(categoryIdentifier: string, entityIdentifier: string) { const url = `/api/v1/Entity/${categoryIdentifier}/${entityIdentifier}`; return this.http.delete(url).pipe( tap(() => this.removeOneFromCache(entityIdentifier)) ); } // 新增/更新直接使用父类方法,路径符合API要求 }
总结
两种方案都能满足你的需求:
- 自定义
HttpUrlGenerator适合全局统一处理多个实体的URL规则,代码复用性高; - 重写
EntityCollectionServiceBase方法更灵活,适合单个实体的特殊业务场景。
内容的提问来源于stack exchange,提问作者artur shevtsov
相关产品推荐
相关产品推荐

