diff --git a/.changeset/good-jars-turn.md b/.changeset/good-jars-turn.md new file mode 100644 index 0000000000..3ba4cb1d36 --- /dev/null +++ b/.changeset/good-jars-turn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': minor +--- + +add IdentityApi support diff --git a/plugins/search/package.json b/plugins/search/package.json index 5c84748e06..dc0041c7a7 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "0.4.0", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search/src/apis.test.ts b/plugins/search/src/apis.test.ts index 64a5207d6d..09b8dc48e6 100644 --- a/plugins/search/src/apis.test.ts +++ b/plugins/search/src/apis.test.ts @@ -26,8 +26,20 @@ describe('apis', () => { const baseUrl = 'https://base-url.com/'; const getBaseUrl = jest.fn().mockResolvedValue(baseUrl); + + const token = 'AUTHTOKEN'; + const withToken = jest.fn().mockResolvedValue(token); + const withoutToken = jest.fn().mockResolvedValue(undefined); + const createIdentityApiMock = (getIdToken: any) => ({ + getIdToken, + getUserId: jest.fn(), + getProfile: jest.fn(), + signOut: jest.fn(), + }); + const client = new SearchClient({ discoveryApi: { getBaseUrl }, + identityApi: createIdentityApiMock(withoutToken), }); const json = jest.fn(); @@ -41,7 +53,21 @@ describe('apis', () => { it('Fetch is called with expected URL (including stringified Q params)', async () => { await client.query(query); expect(getBaseUrl).toHaveBeenLastCalledWith('search/query'); - expect(fetch).toHaveBeenLastCalledWith(`${baseUrl}?term=&pageCursor=`); + expect(fetch).toHaveBeenLastCalledWith(`${baseUrl}?term=&pageCursor=`, { + headers: {}, + }); + }); + + it('Sets Authorization if token is available', async () => { + const authedClient = new SearchClient({ + discoveryApi: { getBaseUrl }, + identityApi: createIdentityApiMock(withToken), + }); + await authedClient.query(query); + expect(getBaseUrl).toHaveBeenLastCalledWith('search/query'); + expect(fetch).toHaveBeenLastCalledWith(`${baseUrl}?term=&pageCursor=`, { + headers: { Authorization: `Bearer ${token}` }, + }); }); it('Resolves JSON from fetch response', async () => { diff --git a/plugins/search/src/apis.ts b/plugins/search/src/apis.ts index 5e039cbb84..8d618116be 100644 --- a/plugins/search/src/apis.ts +++ b/plugins/search/src/apis.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createApiRef, DiscoveryApi } from '@backstage/core'; +import { createApiRef, DiscoveryApi, IdentityApi } from '@backstage/core'; import { SearchQuery, SearchResultSet } from '@backstage/search-common'; import qs from 'qs'; @@ -29,17 +29,25 @@ export interface SearchApi { export class SearchClient implements SearchApi { private readonly discoveryApi: DiscoveryApi; + private readonly identityApi: IdentityApi; - constructor(options: { discoveryApi: DiscoveryApi }) { + constructor(options: { + discoveryApi: DiscoveryApi; + identityApi: IdentityApi; + }) { this.discoveryApi = options.discoveryApi; + this.identityApi = options.identityApi; } async query(query: SearchQuery): Promise { + const token = await this.identityApi.getIdToken(); const queryString = qs.stringify(query); const url = `${await this.discoveryApi.getBaseUrl( 'search/query', )}?${queryString}`; - const response = await fetch(url); + const response = await fetch(url, { + headers: token ? { Authorization: `Bearer ${token}` } : {}, + }); return response.json(); } } diff --git a/plugins/search/src/plugin.ts b/plugins/search/src/plugin.ts index 45987a3749..a0f2103c5f 100644 --- a/plugins/search/src/plugin.ts +++ b/plugins/search/src/plugin.ts @@ -20,6 +20,7 @@ import { createRoutableExtension, discoveryApiRef, createComponentExtension, + identityApiRef, } from '@backstage/core'; import { SearchClient, searchApiRef } from './apis'; @@ -38,9 +39,9 @@ export const searchPlugin = createPlugin({ apis: [ createApiFactory({ api: searchApiRef, - deps: { discoveryApi: discoveryApiRef }, - factory: ({ discoveryApi }) => { - return new SearchClient({ discoveryApi }); + deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef }, + factory: ({ discoveryApi, identityApi }) => { + return new SearchClient({ discoveryApi, identityApi }); }, }), ],