From 0c4ee1876f1f8773cda2ba2fc69e9873d066bb53 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Fri, 27 Aug 2021 15:34:33 +0200 Subject: [PATCH] Modify app impl to contain a reference to apiRegistry. Store additional, late registered and lazy loaded APIs in the registry as well. Route paths, route objs and others are collected already on late reg, this adds APIs to be collected also. Signed-off-by: Jussi Hallila --- .changeset/great-humans-return.md | 7 +++++ packages/core-app-api/src/app/App.tsx | 40 ++++++++++++++++++--------- 2 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 .changeset/great-humans-return.md diff --git a/.changeset/great-humans-return.md b/.changeset/great-humans-return.md new file mode 100644 index 0000000000..bb35069161 --- /dev/null +++ b/.changeset/great-humans-return.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-app-api': patch +--- + +Store additional, late registered and lazy loaded APIs in the registry as well. +Route paths, route objs and others are collected already on late reg, this adds APIs to be collected also. +Enables late registration of plugins into the application and updates ApiHolder when additional plugins have been added in. diff --git a/packages/core-app-api/src/app/App.tsx b/packages/core-app-api/src/app/App.tsx index 7857c8b35f..21d79e6926 100644 --- a/packages/core-app-api/src/app/App.tsx +++ b/packages/core-app-api/src/app/App.tsx @@ -198,6 +198,7 @@ export class PrivateAppImpl implements BackstageApp { private readonly bindRoutes: AppOptions['bindRoutes']; private readonly identityApi = new AppIdentity(); + private readonly apiFactoryRegistry: ApiFactoryRegistry; constructor(options: FullAppOptions) { this.apis = options.apis; @@ -208,6 +209,7 @@ export class PrivateAppImpl implements BackstageApp { this.configLoader = options.configLoader; this.defaultApis = options.defaultApis; this.bindRoutes = options.bindRoutes; + this.apiFactoryRegistry = new ApiFactoryRegistry(); } getPlugins(): BackstagePlugin[] { @@ -388,17 +390,27 @@ export class PrivateAppImpl implements BackstageApp { private getApiHolder(): ApiHolder { if (this.apiHolder) { + // Register additional plugins if they have been added. + // Routes and other config options are updated above when children change + for (const plugin of this.plugins) { + for (const factory of plugin.getApis()) { + if (!this.apiFactoryRegistry.get(factory.api)) { + this.apiFactoryRegistry.register('default', factory); + } + } + } + ApiResolver.validateFactories( + this.apiFactoryRegistry, + this.apiFactoryRegistry.getAllApis(), + ); return this.apiHolder; } - - const registry = new ApiFactoryRegistry(); - - registry.register('static', { + this.apiFactoryRegistry.register('static', { api: appThemeApiRef, deps: {}, factory: () => AppThemeSelector.createWithStorage(this.themes), }); - registry.register('static', { + this.apiFactoryRegistry.register('static', { api: configApiRef, deps: {}, factory: () => { @@ -410,7 +422,7 @@ export class PrivateAppImpl implements BackstageApp { return this.configApi; }, }); - registry.register('static', { + this.apiFactoryRegistry.register('static', { api: identityApiRef, deps: {}, factory: () => this.identityApi, @@ -418,18 +430,18 @@ export class PrivateAppImpl implements BackstageApp { // It's possible to replace the feature flag API, but since we must have at least // one implementation we add it here directly instead of through the defaultApis. - registry.register('default', { + this.apiFactoryRegistry.register('default', { api: featureFlagsApiRef, deps: {}, factory: () => new LocalStorageFeatureFlags(), }); for (const factory of this.defaultApis) { - registry.register('default', factory); + this.apiFactoryRegistry.register('default', factory); } for (const plugin of this.plugins) { for (const factory of plugin.getApis()) { - if (!registry.register('default', factory)) { + if (!this.apiFactoryRegistry.register('default', factory)) { throw new Error( `Plugin ${plugin.getId()} tried to register duplicate or forbidden API factory for ${ factory.api @@ -440,17 +452,19 @@ export class PrivateAppImpl implements BackstageApp { } for (const factory of this.apis) { - if (!registry.register('app', factory)) { + if (!this.apiFactoryRegistry.register('app', factory)) { throw new Error( `Duplicate or forbidden API factory for ${factory.api} in app`, ); } } - ApiResolver.validateFactories(registry, registry.getAllApis()); - - this.apiHolder = new ApiResolver(registry); + ApiResolver.validateFactories( + this.apiFactoryRegistry, + this.apiFactoryRegistry.getAllApis(), + ); + this.apiHolder = new ApiResolver(this.apiFactoryRegistry); return this.apiHolder; }