From 1f384c56443fc553ca6e3f72db009a1a524d1815 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 2 Sep 2022 11:24:17 +0200 Subject: [PATCH] backend-app-api: nicer error messaging when service deps are missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Patrik Oldsberg --- .changeset/tiny-rocks-flash.md | 5 ++++ .../src/wiring/ServiceRegistry.test.ts | 20 ++++++++++++++++ .../src/wiring/ServiceRegistry.ts | 24 ++++++++++++++----- 3 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 .changeset/tiny-rocks-flash.md diff --git a/.changeset/tiny-rocks-flash.md b/.changeset/tiny-rocks-flash.md new file mode 100644 index 0000000000..32b467a6af --- /dev/null +++ b/.changeset/tiny-rocks-flash.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Improved error messaging when failing to instantiate services. diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts index d5b688c0de..94ec77eea8 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts @@ -220,4 +220,24 @@ describe('ServiceRegistry', () => { expect(innerFactory).toHaveBeenCalledWith('catalog'); expect(innerFactory).toHaveBeenCalledWith('scaffolder'); }); + + it('should throw if dependencies are not available', async () => { + const myFactory = createServiceFactory({ + service: ref1, + deps: { dep: ref2 }, + async factory({ dep }) { + return async pluginId => { + const d = await dep(pluginId); + return { x: d.x, pluginId }; + }; + }, + }); + + const registry = new ServiceRegistry([myFactory]); + const factory = registry.get(ref1)!; + + await expect(factory('catalog')).rejects.toThrow( + "Failed to instantiate service '1' for 'catalog'. The following dependent services are missing: '2'", + ); + }); }); diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.ts index 9df092db42..f8d99bffd8 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.ts @@ -56,12 +56,24 @@ export class ServiceRegistry { let implementation = this.#implementations.get(factory); if (!implementation) { - const factoryDeps = Object.fromEntries( - Object.entries(factory.deps).map(([name, serviceRef]) => [ - name, - this.get(serviceRef)!, // TODO: throw - ]), - ); + const missingRefs = new Array>(); + const factoryDeps: { [name in string]: FactoryFunc } = {}; + + for (const [name, serviceRef] of Object.entries(factory.deps)) { + const target = this.get(serviceRef); + if (!target) { + missingRefs.push(serviceRef); + } else { + factoryDeps[name] = target; + } + } + + if (missingRefs.length) { + const missing = missingRefs.map(r => `'${r.id}'`).join(', '); + throw new Error( + `Failed to instantiate service '${ref.id}' for '${pluginId}'. The following dependent services are missing: ${missing}`, + ); + } implementation = { factoryFunc: factory.factory(factoryDeps),