diff --git a/.changeset/mean-adults-argue.md b/.changeset/mean-adults-argue.md new file mode 100644 index 0000000000..2ba26f165d --- /dev/null +++ b/.changeset/mean-adults-argue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-proxy-backend': minor +--- + +The proxy-backend now automatically reloads configuration when app-config.yaml is updated. diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts index 3bfcc889f4..d3f7718c58 100644 --- a/plugins/proxy-backend/src/service/router.test.ts +++ b/plugins/proxy-backend/src/service/router.test.ts @@ -57,6 +57,55 @@ describe('createRouter', () => { }); expect(router).toBeDefined(); }); + + it('should be able to observe the config', async () => { + const logger = getVoidLogger(); + + // Grab the subscriber function and use mutable config data to mock a config file change + let subscriber: () => void; + const mutableConfigData: any = { + backend: { + baseUrl: 'https://example.com:7007', + listen: { + port: 7007, + }, + }, + proxy: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, + }, + }, + }; + + const mockConfig = Object.assign(new ConfigReader(mutableConfigData), { + subscribe: (s: () => void) => { + subscriber = s; + return { unsubscribe: () => {} }; + }, + }); + + const discovery = SingleHostDiscovery.fromConfig(mockConfig); + const router = await createRouter({ + config: mockConfig, + logger, + discovery, + }); + expect(router).toBeDefined(); + + expect(router.stack[0].regexp).toEqual(/^\/test\/?(?=\/|$)/i); + expect(router.stack[1]).toBeUndefined(); + + mutableConfigData.proxy['/test2'] = { + target: 'https://example.com', + }; + subscriber!(); + + expect(router.stack[0].regexp).toEqual(/^\/test\/?(?=\/|$)/i); + expect(router.stack[1].regexp).toEqual(/^\/test2\/?(?=\/|$)/i); + }); }); describe('where buildMiddleware would fail', () => { diff --git a/plugins/proxy-backend/src/service/router.ts b/plugins/proxy-backend/src/service/router.ts index ca2c7870d8..3a6323eb2f 100644 --- a/plugins/proxy-backend/src/service/router.ts +++ b/plugins/proxy-backend/src/service/router.ts @@ -186,8 +186,34 @@ export async function createRouter( const { pathname: pathPrefix } = new URL(externalUrl); const proxyConfig = options.config.getOptional('proxy') ?? {}; + configureMiddlewares(options, router, pathPrefix, proxyConfig); - Object.entries(proxyConfig).forEach(([route, proxyRouteConfig]) => { + if (options.config.subscribe) { + let currentKey = JSON.stringify(proxyConfig); + + options.config.subscribe(() => { + const newProxyConfig = options.config.getOptional('proxy') ?? {}; + const newKey = JSON.stringify(newProxyConfig); + + if (currentKey !== newKey) { + currentKey = newKey; + + router.stack = []; + configureMiddlewares(options, router, pathPrefix, newProxyConfig); + } + }); + } + + return router; +} + +function configureMiddlewares( + options: RouterOptions, + router: express.Router, + pathPrefix: string, + proxyConfig: any, +) { + Object.entries(proxyConfig).forEach(([route, proxyRouteConfig]) => { try { router.use( route, @@ -201,6 +227,4 @@ export async function createRouter( } } }); - - return router; }