diff --git a/.changeset/chilled-pigs-march.md b/.changeset/chilled-pigs-march.md new file mode 100644 index 0000000000..dd50833324 --- /dev/null +++ b/.changeset/chilled-pigs-march.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Deprecate the `getPath` option for the `httpRouterServiceFactory` and more generally the ability to configure plugin API paths to be anything else than `/api/:pluginId/`. Requests towards `/api/*` that do not match an installed plugin will also no longer be handled by the index router, typically instead returning a 404. diff --git a/docs/backend-system/core-services/http-router.md b/docs/backend-system/core-services/http-router.md index e976d2c06c..4dfa7d80e1 100644 --- a/docs/backend-system/core-services/http-router.md +++ b/docs/backend-system/core-services/http-router.md @@ -39,20 +39,4 @@ createBackendPlugin({ ## Configuring the service -There's additional configuration that you can optionally pass to setup the `httpRouter` core service. - -- `getPath` - Can be used to generate a path for each plugin. Currently defaults to `/api/${pluginId}` - -You can configure these additional options by adding an override for the core service when calling `createBackend` like follows: - -```ts -import { httpRouterServiceFactory } from '@backstage/backend-app-api'; - -const backend = createBackend(); - -backend.add( - httpRouterServiceFactory({ - getPath: (pluginId: string) => `/plugins/${pluginId}`, - }), -); -``` +This service does not have any configuration options. diff --git a/docs/backend-system/core-services/root-http-router.md b/docs/backend-system/core-services/root-http-router.md index 8b9de00507..84be48cf87 100644 --- a/docs/backend-system/core-services/root-http-router.md +++ b/docs/backend-system/core-services/root-http-router.md @@ -7,6 +7,8 @@ description: Documentation for the Root Http Router service The root HTTP router is a service that allows you to register routes on the root of the backend service. This is useful for things like health checks, or other routes that you want to expose on the root of the backend service. It is used as the base router that backs the `httpRouter` service. Most likely you won't need to use this service directly, but rather use the `httpRouter` service. +The `/api/:pluginId/` path prefix is reserved for use by plugins to register their own routes via the [HttpRouter](./http-router.md) service. + ## Using the service The following example shows how to get the root HTTP router service in your `example` backend plugin to register a health check route. @@ -74,3 +76,5 @@ backend.add( }), ); ``` + +Note that requests towards `/api/*` will always fall through the `routes` if there is no matching plugin route, and never be caught by the configured `indexPath`. diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/httpRouterServiceFactory.ts b/packages/backend-app-api/src/services/implementations/httpRouter/httpRouterServiceFactory.ts index 5b881dca4c..f8ccdde780 100644 --- a/packages/backend-app-api/src/services/implementations/httpRouter/httpRouterServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/httpRouter/httpRouterServiceFactory.ts @@ -43,6 +43,7 @@ export const httpRouterServiceFactory = createServiceFactory( deps: { plugin: coreServices.pluginMetadata, config: coreServices.rootConfig, + logger: coreServices.logger, lifecycle: coreServices.lifecycle, rootHttpRouter: coreServices.rootHttpRouter, auth: coreServices.auth, @@ -52,10 +53,16 @@ export const httpRouterServiceFactory = createServiceFactory( auth, httpAuth, config, + logger, plugin, rootHttpRouter, lifecycle, }) { + if (options?.getPath) { + logger.warn( + `DEPRECATION WARNING: The 'getPath' option for HttpRouterService is deprecated. The ability to reconfigure the '/api/' path prefix for plugins will be removed in the future.`, + ); + } const getPath = options?.getPath ?? (id => `/api/${id}`); const path = getPath(plugin.getId()); diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.test.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.test.ts index 86c117f7e0..af8340c91e 100644 --- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.test.ts +++ b/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.test.ts @@ -89,4 +89,20 @@ describe('DefaultRootHttpRouter', () => { expect('test').toBe('test'); }); + + it('should treat unknown /api/ routes as 404', async () => { + const router = DefaultRootHttpRouter.create(); + const app = express(); + app.use(router.handler()); + + router.use('/api/app', (_req, res) => res.status(201).end()); + router.use('/api/catalog', (_req, res) => res.status(202).end()); + + await request(app).get('/').expect(201); + await request(app).get('/api/catalog').expect(202); + await request(app).get('/unknown').expect(201); + await request(app).get('/api/unknown').expect(404); + + expect('test').toBe('test'); + }); }); diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.ts index 0a144af494..9d7d1de120 100644 --- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.ts +++ b/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.ts @@ -66,6 +66,12 @@ export class DefaultRootHttpRouter implements RootHttpRouterService { private constructor(indexPath?: string) { this.#indexPath = indexPath; this.#router.use(this.#namedRoutes); + + // Any request with a /api/ prefix will skip the index router, even if no named router matches + this.#router.use('/api/', (_req, _res, next) => { + next('router'); + }); + if (this.#indexPath) { this.#router.use(this.#indexRouter); }