diff --git a/.changeset/rotten-needles-relax.md b/.changeset/rotten-needles-relax.md index a34d0a7cb4..ef389402aa 100644 --- a/.changeset/rotten-needles-relax.md +++ b/.changeset/rotten-needles-relax.md @@ -2,4 +2,6 @@ '@backstage/plugin-catalog-node': minor --- -The `catalogServiceRef` now have its own accompanying `CatalogService` interface, which also supports passing Backstage `credentials` objects in addition to tokens. In addition, it has been promoted from the `/alpha` export and is now available from the main `@backstage/plugin-catalog-node` entry point. +The `catalogServiceRef` now has its own accompanying `CatalogService` interface that requires Backstage `credentials` objects to be passed. This new version of the `catalogServiceRef` has been promoted and is now available via the main `@backstage/plugin-catalog-node` entry point. + +The old `catalogServiceRef` with the old `CatalogApi` type is still available from the `/alpha` entry point. diff --git a/plugins/catalog-node/report.api.md b/plugins/catalog-node/report.api.md index f063e7944b..e196fff230 100644 --- a/plugins/catalog-node/report.api.md +++ b/plugins/catalog-node/report.api.md @@ -11,8 +11,6 @@ import { AnalyzeLocationExistingEntity } from '@backstage/plugin-catalog-common' import { AnalyzeLocationRequest } from '@backstage/plugin-catalog-common'; import { AnalyzeLocationResponse } from '@backstage/plugin-catalog-common'; import { BackstageCredentials } from '@backstage/backend-plugin-api'; -import { CatalogApi } from '@backstage/catalog-client'; -import { CatalogRequestOptions } from '@backstage/catalog-client'; import { CompoundEntityRef } from '@backstage/catalog-model'; import { Entity } from '@backstage/catalog-model'; import { GetEntitiesByRefsRequest } from '@backstage/catalog-client'; @@ -120,77 +118,77 @@ export type CatalogProcessorResult = | CatalogProcessorRefreshKeysResult; // @public -export interface CatalogService extends CatalogApi { +export interface CatalogService { // (undocumented) addLocation( location: AddLocationRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) getEntities( - request?: GetEntitiesRequest, - options?: CatalogServiceRequestOptions, + request: GetEntitiesRequest | undefined, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) getEntitiesByRefs( request: GetEntitiesByRefsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) getEntityAncestors( request: GetEntityAncestorsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) getEntityByRef( entityRef: string | CompoundEntityRef, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) getEntityFacets( request: GetEntityFacetsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) getLocationByEntity( entityRef: string | CompoundEntityRef, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) getLocationById( id: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) getLocationByRef( locationRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) queryEntities( - request?: QueryEntitiesRequest, - options?: CatalogServiceRequestOptions, + request: QueryEntitiesRequest | undefined, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) refreshEntity( entityRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) removeEntityByUid( uid: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) removeLocationById( id: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; // (undocumented) validateEntity( entity: Entity, locationRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; } @@ -202,9 +200,9 @@ export const catalogServiceRef: ServiceRef< >; // @public (undocumented) -export interface CatalogServiceRequestOptions extends CatalogRequestOptions { +export interface CatalogServiceRequestOptions { // (undocumented) - credentials?: BackstageCredentials; + credentials: BackstageCredentials; } // @public diff --git a/plugins/catalog-node/src/catalogService.test.ts b/plugins/catalog-node/src/catalogService.test.ts index 387817df98..e6f2668d70 100644 --- a/plugins/catalog-node/src/catalogService.test.ts +++ b/plugins/catalog-node/src/catalogService.test.ts @@ -118,57 +118,4 @@ describe('catalogServiceRef', () => { { credentials: mockCredentials.service() }, ); }); - - it('should call with token', async () => { - expect.assertions(1); - - server.use( - rest.get('http://localhost/api/catalog/entities', (req, res, ctx) => { - expect(req.headers.get('authorization')).toBe( - mockCredentials.user.header(), - ); - return res(ctx.json({})); - }), - ); - const tester = ServiceFactoryTester.from( - createServiceFactory({ - service: createServiceRef({ id: 'unused-dummy' }), - deps: {}, - factory() {}, - }), - { dependencies: [mockServices.discovery.factory()] }, - ); - - const catalogService = await tester.getService(catalogServiceRef); - - await catalogService.getEntities( - {}, - { - token: mockCredentials.user.token(), - }, - ); - }); - - it('should call without credentials', async () => { - expect.assertions(1); - - server.use( - rest.get('http://localhost/api/catalog/entities', (req, res, ctx) => { - expect(req.headers.get('authorization')).toBeFalsy(); - return res(ctx.json({})); - }), - ); - const tester = ServiceFactoryTester.from( - createServiceFactory({ - service: createServiceRef({ id: 'unused-dummy' }), - deps: {}, - factory() {}, - }), - { dependencies: [mockServices.discovery.factory()] }, - ); - - const catalogService = await tester.getService(catalogServiceRef); - - await catalogService.getEntities(); - }); }); diff --git a/plugins/catalog-node/src/catalogService.ts b/plugins/catalog-node/src/catalogService.ts index 8b81bc68fd..5e8c920dad 100644 --- a/plugins/catalog-node/src/catalogService.ts +++ b/plugins/catalog-node/src/catalogService.ts @@ -19,7 +19,6 @@ import { createServiceRef, coreServices, BackstageCredentials, - DiscoveryService, AuthService, } from '@backstage/backend-plugin-api'; import { @@ -46,192 +45,229 @@ import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; /** * @public */ -export interface CatalogServiceRequestOptions extends CatalogRequestOptions { - credentials?: BackstageCredentials; +export interface CatalogServiceRequestOptions { + credentials: BackstageCredentials; } /** * A version of the {@link @backstage/catalog-client#CatalogApi | CatalogApi} that - * accepts backend credentials in addition to a token. + * requires backend credentials to be passed instead of a token. * * @public */ -export interface CatalogService extends CatalogApi { +export interface CatalogService { getEntities( - request?: GetEntitiesRequest, - options?: CatalogServiceRequestOptions, + request: GetEntitiesRequest | undefined, + options: CatalogServiceRequestOptions, ): Promise; getEntitiesByRefs( request: GetEntitiesByRefsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; queryEntities( - request?: QueryEntitiesRequest, - options?: CatalogServiceRequestOptions, + request: QueryEntitiesRequest | undefined, + options: CatalogServiceRequestOptions, ): Promise; getEntityAncestors( request: GetEntityAncestorsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; getEntityByRef( entityRef: string | CompoundEntityRef, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; removeEntityByUid( uid: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; refreshEntity( entityRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; getEntityFacets( request: GetEntityFacetsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; getLocationById( id: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; getLocationByRef( locationRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; addLocation( location: AddLocationRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; removeLocationById( id: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; getLocationByEntity( entityRef: string | CompoundEntityRef, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; validateEntity( entity: Entity, locationRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise; } -class DefaultCatalogService extends CatalogClient { +class DefaultCatalogService implements CatalogService { readonly #auth: AuthService; + readonly #catalogApi: CatalogApi; constructor({ - discoveryApi, + catalogApi, auth, }: { - discoveryApi: DiscoveryService; + catalogApi: CatalogApi; auth: AuthService; }) { - super({ discoveryApi }); + this.#catalogApi = catalogApi; this.#auth = auth; } async getEntities( - request?: GetEntitiesRequest, - options?: CatalogServiceRequestOptions, + request: GetEntitiesRequest | undefined, + options: CatalogServiceRequestOptions, ): Promise { - return super.getEntities(request, await this.#getOptions(options)); + return this.#catalogApi.getEntities( + request, + await this.#getOptions(options), + ); } async getEntitiesByRefs( request: GetEntitiesByRefsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.getEntitiesByRefs(request, await this.#getOptions(options)); + return this.#catalogApi.getEntitiesByRefs( + request, + await this.#getOptions(options), + ); } async queryEntities( - request?: QueryEntitiesRequest, - options?: CatalogServiceRequestOptions, + request: QueryEntitiesRequest | undefined, + options: CatalogServiceRequestOptions, ): Promise { - return super.queryEntities(request, await this.#getOptions(options)); + return this.#catalogApi.queryEntities( + request, + await this.#getOptions(options), + ); } async getEntityAncestors( request: GetEntityAncestorsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.getEntityAncestors(request, await this.#getOptions(options)); + return this.#catalogApi.getEntityAncestors( + request, + await this.#getOptions(options), + ); } async getEntityByRef( entityRef: string | CompoundEntityRef, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.getEntityByRef(entityRef, await this.#getOptions(options)); + return this.#catalogApi.getEntityByRef( + entityRef, + await this.#getOptions(options), + ); } async removeEntityByUid( uid: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.removeEntityByUid(uid, await this.#getOptions(options)); + return this.#catalogApi.removeEntityByUid( + uid, + await this.#getOptions(options), + ); } async refreshEntity( entityRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.refreshEntity(entityRef, await this.#getOptions(options)); + return this.#catalogApi.refreshEntity( + entityRef, + await this.#getOptions(options), + ); } async getEntityFacets( request: GetEntityFacetsRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.getEntityFacets(request, await this.#getOptions(options)); + return this.#catalogApi.getEntityFacets( + request, + await this.#getOptions(options), + ); } async getLocationById( id: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.getLocationById(id, await this.#getOptions(options)); + return this.#catalogApi.getLocationById( + id, + await this.#getOptions(options), + ); } async getLocationByRef( locationRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.getLocationByRef(locationRef, await this.#getOptions(options)); + return this.#catalogApi.getLocationByRef( + locationRef, + await this.#getOptions(options), + ); } async addLocation( location: AddLocationRequest, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.addLocation(location, await this.#getOptions(options)); + return this.#catalogApi.addLocation( + location, + await this.#getOptions(options), + ); } async removeLocationById( id: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.removeLocationById(id, await this.#getOptions(options)); + return this.#catalogApi.removeLocationById( + id, + await this.#getOptions(options), + ); } async getLocationByEntity( entityRef: string | CompoundEntityRef, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.getLocationByEntity( + return this.#catalogApi.getLocationByEntity( entityRef, await this.#getOptions(options), ); @@ -240,9 +276,9 @@ class DefaultCatalogService extends CatalogClient { async validateEntity( entity: Entity, locationRef: string, - options?: CatalogServiceRequestOptions, + options: CatalogServiceRequestOptions, ): Promise { - return super.validateEntity( + return this.#catalogApi.validateEntity( entity, locationRef, await this.#getOptions(options), @@ -250,18 +286,12 @@ class DefaultCatalogService extends CatalogClient { } async #getOptions( - options?: CatalogServiceRequestOptions, - ): Promise { - if (options?.token) { - return options; - } - if (options?.credentials) { - return this.#auth.getPluginRequestToken({ - onBehalfOf: options.credentials, - targetPluginId: 'catalog', - }); - } - return options; + options: CatalogServiceRequestOptions, + ): Promise { + return this.#auth.getPluginRequestToken({ + onBehalfOf: options.credentials, + targetPluginId: 'catalog', + }); } } @@ -279,8 +309,11 @@ export const catalogServiceRef = createServiceRef({ auth: coreServices.auth, discoveryApi: coreServices.discovery, }, - async factory(deps) { - return new DefaultCatalogService(deps); + async factory({ auth, discoveryApi }) { + return new DefaultCatalogService({ + auth, + catalogApi: new CatalogClient({ discoveryApi }), + }); }, }), });