fix(api): derive host from storefront domain
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Every storefront, including nested subdomains, uses its matching api.<hostname> endpoint.
This commit is contained in:
@@ -16,7 +16,7 @@ describe('ApiBootstrapProvider', () => {
|
||||
provideHttpClientTesting(),
|
||||
{
|
||||
provide: ApiConfigService,
|
||||
useValue: { getBaseUrl: () => 'https://gorbushka.market/backend' }
|
||||
useValue: { getBaseUrl: () => 'https://api.gorbushka.market' }
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -30,7 +30,7 @@ describe('ApiBootstrapProvider', () => {
|
||||
it('loads bootstrap from the same tenant API base as every other request', () => {
|
||||
provider.loadBootstrap().subscribe();
|
||||
|
||||
const request = httpTesting.expectOne('https://gorbushka.market/backend/bootstrap');
|
||||
const request = httpTesting.expectOne('https://api.gorbushka.market/bootstrap');
|
||||
expect(request.request.method).toBe('GET');
|
||||
request.flush({});
|
||||
});
|
||||
|
||||
@@ -9,10 +9,10 @@ describe('ApiConfigService', () => {
|
||||
beforeEach(() => {
|
||||
tenantResolver = jasmine.createSpyObj<TenantResolverService>(
|
||||
'TenantResolverService',
|
||||
['getHostname', 'getOrigin', 'getTenantKey', 'isLocalhost']
|
||||
['getHostname', 'getProtocol', 'getTenantKey', 'isLocalhost']
|
||||
);
|
||||
tenantResolver.getTenantKey.and.returnValue('gorbushka');
|
||||
tenantResolver.getOrigin.and.returnValue('https://gorbushka.market');
|
||||
tenantResolver.getProtocol.and.returnValue('https:');
|
||||
tenantResolver.isLocalhost.and.returnValue(false);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
@@ -28,26 +28,30 @@ describe('ApiConfigService', () => {
|
||||
it('uses the current customer hostname for the production API base URL', () => {
|
||||
tenantResolver.getHostname.and.returnValue('gorbushka.market');
|
||||
|
||||
expect(service.getBaseUrl()).toBe('https://gorbushka.market/backend');
|
||||
expect(service.getBaseUrl()).toBe('https://api.gorbushka.market');
|
||||
});
|
||||
|
||||
it('keeps www traffic on the same browser origin', () => {
|
||||
tenantResolver.getHostname.and.returnValue('www.gorbushka.market');
|
||||
tenantResolver.getOrigin.and.returnValue('https://www.gorbushka.market');
|
||||
it('preserves every storefront subdomain in the API hostname', () => {
|
||||
tenantResolver.getHostname.and.returnValue('store1.example.com');
|
||||
|
||||
expect(service.getBaseUrl()).toBe('https://www.gorbushka.market/backend');
|
||||
expect(service.getBaseUrl()).toBe('https://api.store1.example.com');
|
||||
});
|
||||
|
||||
it('preserves www like any other storefront subdomain', () => {
|
||||
tenantResolver.getHostname.and.returnValue('www.gorbushka.market');
|
||||
|
||||
expect(service.getBaseUrl()).toBe('https://api.www.gorbushka.market');
|
||||
});
|
||||
|
||||
it('preserves the API namespace when targeting a tenant backend', () => {
|
||||
tenantResolver.getHostname.and.returnValue('gorbushka.market');
|
||||
|
||||
expect(service.toApiUrl('/api/v2/storefront/cart'))
|
||||
.toBe('https://gorbushka.market/backend/api/v2/storefront/cart');
|
||||
.toBe('https://api.gorbushka.market/api/v2/storefront/cart');
|
||||
});
|
||||
|
||||
it('does not duplicate the API prefix for localhost proxy requests', () => {
|
||||
tenantResolver.getHostname.and.returnValue('localhost');
|
||||
tenantResolver.getOrigin.and.returnValue('http://localhost:4200');
|
||||
tenantResolver.getTenantKey.and.returnValue('default');
|
||||
tenantResolver.isLocalhost.and.returnValue(true);
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ export class ApiConfigService {
|
||||
|
||||
getBaseUrl(): string {
|
||||
const hostname = this.tenantResolver.getHostname();
|
||||
const apiHostname = hostname.startsWith('www.') ? hostname.slice(4) : hostname;
|
||||
const origin = this.tenantResolver.getOrigin();
|
||||
const protocol = this.tenantResolver.getProtocol();
|
||||
const tenantKey = this.tenantResolver.getTenantKey();
|
||||
const tenantMap = (environment as any).tenantApiBaseUrls as Record<string, string> | undefined;
|
||||
const localhostUrl = (environment as any).localhostApiUrl as string | undefined;
|
||||
@@ -19,14 +18,14 @@ export class ApiConfigService {
|
||||
|
||||
if (this.tenantResolver.isLocalhost() && localhostUrl) {
|
||||
url = localhostUrl;
|
||||
} else if (tenantMap?.[hostname] || tenantMap?.[apiHostname]) {
|
||||
url = tenantMap[hostname] ?? tenantMap[apiHostname];
|
||||
} else if (tenantMap?.[hostname]) {
|
||||
url = tenantMap[hostname];
|
||||
} else if (tenantMap?.[tenantKey]) {
|
||||
url = tenantMap[tenantKey];
|
||||
} else if (apiTemplate && origin) {
|
||||
} else if (apiTemplate && hostname) {
|
||||
url = apiTemplate
|
||||
.replace('{origin}', origin)
|
||||
.replace('{hostname}', apiHostname)
|
||||
.replace('{protocol}', protocol)
|
||||
.replace('{hostname}', hostname)
|
||||
.replace('{tenant}', tenantKey);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ export class TenantResolverService {
|
||||
return host.toLowerCase();
|
||||
}
|
||||
|
||||
getOrigin(): string {
|
||||
return this.document?.location?.origin ?? '';
|
||||
getProtocol(): string {
|
||||
return this.document?.location?.protocol ?? 'https:';
|
||||
}
|
||||
|
||||
isLocalhost(): boolean {
|
||||
|
||||
@@ -4,7 +4,7 @@ export const environment = {
|
||||
useMockBootstrapOnLocal: false,
|
||||
fallbackTenantKey: 'default',
|
||||
localhostApiUrl: '/api',
|
||||
tenantApiTemplate: '{origin}/backend',
|
||||
tenantApiTemplate: '{protocol}//api.{hostname}',
|
||||
tenantApiBaseUrls: {},
|
||||
brandName: 'Marketplace',
|
||||
brandFullName: 'Marketplace',
|
||||
|
||||
@@ -5,7 +5,7 @@ export const environment = {
|
||||
useMockBootstrapOnLocal: true,
|
||||
fallbackTenantKey: 'default',
|
||||
localhostApiUrl: '/api',
|
||||
tenantApiTemplate: '{origin}/backend',
|
||||
tenantApiTemplate: '{protocol}//api.{hostname}',
|
||||
tenantApiBaseUrls: {},
|
||||
brandName: 'Marketplace',
|
||||
brandFullName: 'Marketplace',
|
||||
|
||||
Reference in New Issue
Block a user