diff --git a/modules/data/spec/dataservices/default-data.service.spec.ts b/modules/data/spec/dataservices/default-data.service.spec.ts index 352862eefe..876ac3d42d 100644 --- a/modules/data/spec/dataservices/default-data.service.spec.ts +++ b/modules/data/spec/dataservices/default-data.service.spec.ts @@ -543,5 +543,27 @@ describe('DefaultDataServiceFactory', () => { heroDS.getAll(); expect(http.get).toHaveBeenCalledWith(newHeroesUrl, undefined); }); + + it('should keep trailing slash', () => { + const newHeroesUrl = 'some/other/api/heroes/'; + const config: DefaultDataServiceConfig = { + root: '//example.com/api/', + entityHttpResourceUrls: { + Hero: { + entityResourceUrl: '/api/hero/', + collectionResourceUrl: newHeroesUrl, + }, + }, + trailingSlashEndpoints: true, + }; + const factory = new DefaultDataServiceFactory( + http, + httpUrlGenerator, + config + ); + const heroDS = factory.create('Hero'); + heroDS.getAll(); + expect(http.get).toHaveBeenCalledWith(newHeroesUrl, undefined); + }); }); }); diff --git a/modules/data/src/dataservices/default-data-service-config.ts b/modules/data/src/dataservices/default-data-service-config.ts index b4bfff3329..a18f642463 100644 --- a/modules/data/src/dataservices/default-data-service-config.ts +++ b/modules/data/src/dataservices/default-data-service-config.ts @@ -23,4 +23,6 @@ export abstract class DefaultDataServiceConfig { saveDelay?: number; /** request timeout in MS (default: 0)*/ timeout?: number; // + /** to keep trailing slashes or not; false by default */ + trailingSlashEndpoints?: boolean; } diff --git a/modules/data/src/dataservices/default-data.service.ts b/modules/data/src/dataservices/default-data.service.ts index 8ea0578213..76338e1728 100644 --- a/modules/data/src/dataservices/default-data.service.ts +++ b/modules/data/src/dataservices/default-data.service.ts @@ -34,6 +34,7 @@ export class DefaultDataService implements EntityCollectionDataService { protected getDelay = 0; protected saveDelay = 0; protected timeout = 0; + protected trailingSlashEndpoints = false; get name() { return this._name; @@ -53,9 +54,11 @@ export class DefaultDataService implements EntityCollectionDataService { getDelay = 0, saveDelay = 0, timeout: to = 0, + trailingSlashEndpoints = false, } = config || {}; this.delete404OK = delete404OK; - this.entityUrl = httpUrlGenerator.entityResource(entityName, root); + this.entityUrl = httpUrlGenerator.entityResource(entityName, root, + trailingSlashEndpoints); this.entitiesUrl = httpUrlGenerator.collectionResource(entityName, root); this.getDelay = getDelay; this.saveDelay = saveDelay; diff --git a/modules/data/src/dataservices/http-url-generator.ts b/modules/data/src/dataservices/http-url-generator.ts index f5dd3169f7..44fd0456e6 100644 --- a/modules/data/src/dataservices/http-url-generator.ts +++ b/modules/data/src/dataservices/http-url-generator.ts @@ -41,7 +41,8 @@ export abstract class HttpUrlGenerator { * Return the base URL for a single entity resource, * e.g., the base URL to get a single hero by its id */ - abstract entityResource(entityName: string, root: string): string; + abstract entityResource(entityName: string, root: string, + trailingSlashEndpoints: boolean): string; /** * Return the base URL for a collection resource, @@ -77,11 +78,12 @@ export class DefaultHttpUrlGenerator implements HttpUrlGenerator { */ protected getResourceUrls( entityName: string, - root: string + root: string, + trailingSlashEndpoints: boolean = false ): HttpResourceUrls { let resourceUrls = this.knownHttpResourceUrls[entityName]; if (!resourceUrls) { - const nRoot = normalizeRoot(root); + const nRoot = trailingSlashEndpoints ? root: normalizeRoot(root); resourceUrls = { entityResourceUrl: `${nRoot}/${entityName}/`.toLowerCase(), collectionResourceUrl: `${nRoot}/${this.pluralizer.pluralize( @@ -99,8 +101,9 @@ export class DefaultHttpUrlGenerator implements HttpUrlGenerator { * @param root {string} Root path to the resource, e.g., 'some-api` * @returns complete path to resource, e.g, 'some-api/hero' */ - entityResource(entityName: string, root: string): string { - return this.getResourceUrls(entityName, root).entityResourceUrl; + entityResource(entityName: string, root: string, + trailingSlashEndpoints: boolean): string { + return this.getResourceUrls(entityName, root, trailingSlashEndpoints).entityResourceUrl; } /**