diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index d348049157..ed0518485a 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -18,7 +18,7 @@ import { createApp, AlertDisplay, OAuthRequestDialog } from '@backstage/core'; import React, { FC } from 'react'; import Root from './components/Root'; import * as plugins from './plugins'; -import apis from './apis'; +import { apis } from './apis'; import { hot } from 'react-hot-loader/root'; const app = createApp({ diff --git a/packages/app/src/apis.ts b/packages/app/src/apis.ts index 4d78ef1431..9bfc618216 100644 --- a/packages/app/src/apis.ts +++ b/packages/app/src/apis.ts @@ -15,11 +15,11 @@ */ import { - ApiHolder, ApiRegistry, alertApiRef, errorApiRef, AlertApiForwarder, + ConfigApi, ErrorApiForwarder, ErrorAlerter, featureFlagsApiRef, @@ -46,59 +46,64 @@ import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog'; import { gitOpsApiRef, GitOpsRestApi } from '@backstage/plugin-gitops-profiles'; -const builder = ApiRegistry.builder(); +export const apis = (config: ConfigApi) => { + // eslint-disable-next-line no-console + console.log(`Creating APIs for ${config.getString('app.title')}`); -const alertApi = builder.add(alertApiRef, new AlertApiForwarder()); -const errorApi = builder.add( - errorApiRef, - new ErrorAlerter(alertApi, new ErrorApiForwarder()), -); + const builder = ApiRegistry.builder(); -builder.add(storageApiRef, WebStorage.create({ errorApi })); -builder.add(circleCIApiRef, new CircleCIApi()); -builder.add(featureFlagsApiRef, new FeatureFlags()); + const alertApi = builder.add(alertApiRef, new AlertApiForwarder()); + const errorApi = builder.add( + errorApiRef, + new ErrorAlerter(alertApi, new ErrorApiForwarder()), + ); -builder.add(lighthouseApiRef, new LighthouseRestApi('http://localhost:3003')); + builder.add(storageApiRef, WebStorage.create({ errorApi })); + builder.add(circleCIApiRef, new CircleCIApi()); + builder.add(featureFlagsApiRef, new FeatureFlags()); -const oauthRequestApi = builder.add( - oauthRequestApiRef, - new OAuthRequestManager(), -); + builder.add(lighthouseApiRef, new LighthouseRestApi('http://localhost:3003')); -builder.add( - googleAuthApiRef, - GoogleAuth.create({ - apiOrigin: 'http://localhost:7000', - basePath: '/auth/', - oauthRequestApi, - }), -); + const oauthRequestApi = builder.add( + oauthRequestApiRef, + new OAuthRequestManager(), + ); -builder.add( - githubAuthApiRef, - GithubAuth.create({ - apiOrigin: 'http://localhost:7000', - basePath: '/auth/', - oauthRequestApi, - }), -); + builder.add( + googleAuthApiRef, + GoogleAuth.create({ + apiOrigin: 'http://localhost:7000', + basePath: '/auth/', + oauthRequestApi, + }), + ); -builder.add( - techRadarApiRef, - new TechRadar({ - width: 1500, - height: 800, - }), -); + builder.add( + githubAuthApiRef, + GithubAuth.create({ + apiOrigin: 'http://localhost:7000', + basePath: '/auth/', + oauthRequestApi, + }), + ); -builder.add( - catalogApiRef, - new CatalogClient({ - apiOrigin: 'http://localhost:3000', - basePath: '/catalog/api', - }), -); + builder.add( + techRadarApiRef, + new TechRadar({ + width: 1500, + height: 800, + }), + ); -builder.add(gitOpsApiRef, new GitOpsRestApi('http://localhost:3008')); + builder.add( + catalogApiRef, + new CatalogClient({ + apiOrigin: 'http://localhost:3000', + basePath: '/catalog/api', + }), + ); -export default builder.build() as ApiHolder; + builder.add(gitOpsApiRef, new GitOpsRestApi('http://localhost:3008')); + + return builder.build(); +}; diff --git a/packages/backend/README.md b/packages/backend/README.md index e9bf4199ff..64078006e7 100644 --- a/packages/backend/README.md +++ b/packages/backend/README.md @@ -40,7 +40,7 @@ to the backend. These are places where the backend can find some entity descript data to consume and serve. To get started, you can issue the following after starting the backend, from inside -the `packages/catalog-backend` directory: +the `plugins/catalog-backend` directory: ```bash yarn mock-catalog-data diff --git a/packages/core-api/src/app/App.tsx b/packages/core-api/src/app/App.tsx index 3f77d826ae..d7920e6bbd 100644 --- a/packages/core-api/src/app/App.tsx +++ b/packages/core-api/src/app/App.tsx @@ -16,7 +16,7 @@ import React, { ComponentType, FC, useMemo } from 'react'; import { Route, Routes, Navigate } from 'react-router-dom'; import { AppContextProvider } from './AppContext'; -import { BackstageApp, AppComponents, AppConfigLoader } from './types'; +import { BackstageApp, AppComponents, AppConfigLoader, Apis } from './types'; import { BackstagePlugin } from '../plugin'; import { FeatureFlagsRegistryItem } from './FeatureFlags'; import { featureFlagsApiRef } from '../apis/definitions'; @@ -37,7 +37,7 @@ import { ApiAggregator } from '../apis/ApiAggregator'; import { useAsync } from 'react-use'; type FullAppOptions = { - apis: ApiHolder; + apis: Apis; icons: SystemIcons; plugins: BackstagePlugin[]; components: AppComponents; @@ -46,15 +46,17 @@ type FullAppOptions = { }; export class PrivateAppImpl implements BackstageApp { - private readonly apis: ApiHolder; + private apis?: ApiHolder = undefined; private readonly icons: SystemIcons; private readonly plugins: BackstagePlugin[]; private readonly components: AppComponents; private readonly themes: AppTheme[]; private readonly configLoader?: AppConfigLoader; + private apisOrFactory: Apis; + constructor(options: FullAppOptions) { - this.apis = options.apis; + this.apisOrFactory = options.apis; this.icons = options.icons; this.plugins = options.plugins; this.components = options.components; @@ -63,6 +65,9 @@ export class PrivateAppImpl implements BackstageApp { } getApis(): ApiHolder { + if (!this.apis) { + throw new Error('Tried to access APIs before app was loaded'); + } return this.apis; } @@ -176,6 +181,15 @@ export class PrivateAppImpl implements BackstageApp { [appThemeApiRef, AppThemeSelector.createWithStorage(this.themes)], [configApiRef, configReader], ]); + + if (!this.apis) { + if ('get' in this.apisOrFactory) { + this.apis = this.apisOrFactory; + } else { + this.apis = this.apisOrFactory(configReader); + } + } + const apis = new ApiAggregator(this.apis, appApis); const { Router } = this.components; diff --git a/packages/core-api/src/app/types.ts b/packages/core-api/src/app/types.ts index 08547bacfd..e30c79dd73 100644 --- a/packages/core-api/src/app/types.ts +++ b/packages/core-api/src/app/types.ts @@ -18,7 +18,7 @@ import { ComponentType } from 'react'; import { IconComponent, SystemIconKey, SystemIcons } from '../icons'; import { BackstagePlugin } from '../plugin'; import { ApiHolder } from '../apis'; -import { AppTheme } from '../apis/definitions'; +import { AppTheme, ConfigApi } from '../apis/definitions'; import { AppConfig } from '@backstage/config'; export type BootErrorPageProps = { @@ -40,13 +40,16 @@ export type AppComponents = { */ export type AppConfigLoader = () => Promise; +// TODO(Rugvip): Temporary workaround for accessing config when instantiating APIs, we might want to do this differently +export type Apis = ApiHolder | ((config: ConfigApi) => ApiHolder); + export type AppOptions = { /** * A holder of all APIs available in the app. * * Use for example ApiRegistry or ApiTestRegistry. */ - apis?: ApiHolder; + apis?: Apis; /** * Supply icons to override the default ones.