diff --git a/packages/app-defaults/src/defaults/apis.ts b/packages/app-defaults/src/defaults/apis.ts
index c53ce63ada..7ff8ce16bc 100644
--- a/packages/app-defaults/src/defaults/apis.ts
+++ b/packages/app-defaults/src/defaults/apis.ts
@@ -65,17 +65,9 @@ export const apis = [
api: discoveryApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) => {
- let baseUrl;
- try {
- // Try parsing the url relative to the current document origin, if it fails the URL is misformed.
- baseUrl = new URL(
- configApi.getString('backend.baseUrl'),
- document.location.origin,
- ).href.replace(/\/$/, '');
- } catch (err) {
- baseUrl = configApi.getString('backend.baseUrl');
- }
- return UrlPatternDiscovery.compile(`${baseUrl}/api/{{ pluginId }}`);
+ return UrlPatternDiscovery.compile(
+ `${configApi.getString('backend.baseUrl')}/api/{{ pluginId }}`,
+ );
},
}),
createApiFactory({
diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx
index c70b43581a..33b7ad5b9a 100644
--- a/packages/core-app-api/src/app/AppManager.test.tsx
+++ b/packages/core-app-api/src/app/AppManager.test.tsx
@@ -34,6 +34,7 @@ import {
createSubRouteRef,
createRoutableExtension,
analyticsApiRef,
+ useApiHolder,
} from '@backstage/core-plugin-api';
import { AppManager } from './AppManager';
import { AppComponents, AppIcons } from './types';
@@ -569,4 +570,93 @@ describe('Integration Test', () => {
),
]);
});
+
+ it('should add the fully qualified origin when the backend.baseUrl is relative', async () => {
+ const app = new AppManager({
+ apis: [],
+ defaultApis: [],
+ themes: [
+ {
+ id: 'light',
+ title: 'Light Theme',
+ variant: 'light',
+ Provider: ({ children }) => <>{children}>,
+ },
+ ],
+ icons,
+ plugins: [],
+ components,
+ configLoader: async () => [
+ {
+ context: 'test',
+ data: {
+ backend: {
+ baseUrl: '/',
+ },
+ },
+ },
+ ],
+ });
+
+ const Provider = app.getProvider();
+ const ConfigDisplay = () => {
+ const apiHolder = useApiHolder();
+ const config = apiHolder.get(configApiRef);
+ return {config?.getString('backend.baseUrl')};
+ };
+
+ const dom = await renderWithEffects(
+
+
+ ,
+ );
+
+ // Verify that the backend.baseUrl is set correctly by the AppManager.
+ expect(dom.getByText(document.location.origin)).toBeTruthy();
+ });
+
+ it('should NOT change the origin when the backend.baseUrl is absolute', async () => {
+ const backendUrl = 'http://localhost:7007';
+ const app = new AppManager({
+ apis: [],
+ defaultApis: [],
+ themes: [
+ {
+ id: 'light',
+ title: 'Light Theme',
+ variant: 'light',
+ Provider: ({ children }) => <>{children}>,
+ },
+ ],
+ icons,
+ plugins: [],
+ components,
+ configLoader: async () => [
+ {
+ context: 'test',
+ data: {
+ backend: {
+ baseUrl: backendUrl,
+ },
+ },
+ },
+ ],
+ });
+
+ const Provider = app.getProvider();
+ const ConfigDisplay = () => {
+ const apiHolder = useApiHolder();
+ const config = apiHolder.get(configApiRef);
+ return {config?.getString('backend.baseUrl')};
+ };
+
+ const dom = await renderWithEffects(
+
+
+ ,
+ );
+
+ // Verify that the backend.baseUrl is set correctly by the AppManager.
+ expect(dom.getByText(backendUrl)).toBeTruthy();
+ });
});
diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx
index bbd27f84ce..cd571c7799 100644
--- a/packages/core-app-api/src/app/AppManager.tsx
+++ b/packages/core-app-api/src/app/AppManager.tsx
@@ -154,7 +154,34 @@ function useConfigLoader(
};
}
- const configReader = ConfigReader.fromConfigs(config.value ?? []);
+ let configReader = ConfigReader.fromConfigs(config.value ?? []);
+
+ const getFullBackendUrl = () => {
+ // Backend.baseUrl should always be defined.
+ let url;
+ try {
+ url = new URL(
+ configReader.getString('backend.baseUrl'),
+ document.location.origin,
+ ).href.replace(/\/$/, '');
+ } catch (err) {
+ // Backend.baseUrl was not a valid URL. This should be caught during the build process.
+ }
+ return url;
+ };
+
+ const relativeBackendConfig = {
+ data: {
+ backend: {
+ baseUrl: getFullBackendUrl(),
+ },
+ },
+ context: 'relative-override',
+ };
+
+ configReader = ConfigReader.fromConfigs(
+ config.value ? [...config.value, relativeBackendConfig] : [],
+ );
return { api: configReader };
}