feat: allow passing optional filter to getEntityByRefs

this closes #22839

Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
Heikki Hellgren
2024-02-09 08:46:59 +02:00
parent 5fbb3f6e30
commit 6f830bb846
10 changed files with 58 additions and 16 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/catalog-client': patch
'@backstage/plugin-catalog-backend': patch
---
Allow passing optional filter to `getEntitiesByRefs`
+1
View File
@@ -192,6 +192,7 @@ export type EntityOrderQuery =
export interface GetEntitiesByRefsRequest {
entityRefs: string[];
fields?: EntityFieldsQuery | undefined;
filter?: EntityFilterQuery;
}
// @public
@@ -275,6 +275,7 @@ describe('CatalogClient', () => {
};
server.use(
rest.post(`${mockBaseUrl}/entities/by-refs`, async (req, res, ctx) => {
expect(req.url.search).toBe('?filter=kind%3DAPI%2Ckind%3DComponent');
await expect(req.json()).resolves.toEqual({
entityRefs: ['k:n/a', 'k:n/b'],
fields: ['a', 'b'],
@@ -284,7 +285,13 @@ describe('CatalogClient', () => {
);
const response = await client.getEntitiesByRefs(
{ entityRefs: ['k:n/a', 'k:n/b'], fields: ['a', 'b'] },
{
entityRefs: ['k:n/a', 'k:n/b'],
fields: ['a', 'b'],
filter: {
kind: ['API', 'Component'],
},
},
{ token },
);
+18 -12
View File
@@ -15,32 +15,32 @@
*/
import {
Entity,
CompoundEntityRef,
Entity,
parseEntityRef,
stringifyEntityRef,
stringifyLocationRef,
} from '@backstage/catalog-model';
import { ResponseError } from '@backstage/errors';
import {
CATALOG_FILTER_EXISTS,
AddLocationRequest,
AddLocationResponse,
CATALOG_FILTER_EXISTS,
CatalogApi,
GetEntitiesRequest,
GetEntitiesResponse,
CatalogRequestOptions,
GetEntityAncestorsRequest,
GetEntityAncestorsResponse,
Location,
GetEntityFacetsRequest,
GetEntityFacetsResponse,
ValidateEntityResponse,
EntityFilterQuery,
GetEntitiesByRefsRequest,
GetEntitiesByRefsResponse,
GetEntitiesRequest,
GetEntitiesResponse,
GetEntityAncestorsRequest,
GetEntityAncestorsResponse,
GetEntityFacetsRequest,
GetEntityFacetsResponse,
Location,
QueryEntitiesRequest,
EntityFilterQuery,
QueryEntitiesResponse,
ValidateEntityResponse,
} from './types/api';
import { isQueryEntitiesInitialRequest } from './utils';
import { DefaultApiClient, TypedResponse } from './generated';
@@ -177,7 +177,13 @@ export class CatalogClient implements CatalogApi {
): Promise<GetEntitiesByRefsResponse> {
const response = await this.apiClient.getEntitiesByRefs(
{
body: request,
body: {
entityRefs: request.entityRefs,
fields: request.fields,
},
query: {
filter: this.getFilterValue(request.filter),
},
},
options,
);
@@ -281,14 +281,17 @@ export class DefaultApiClient {
// @ts-ignore
request: {
body: GetEntitiesByRefsRequest;
query?: {
filter?: Array<string>;
};
},
options?: RequestOptions,
): Promise<TypedResponse<EntitiesBatchResponse>> {
const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);
const uriTemplate = `/entities/by-refs`;
const uriTemplate = `/entities/by-refs/{?filter*}`;
const uri = parser.parse(uriTemplate).expand({});
const uri = parser.parse(uriTemplate).expand({ ...request.query });
return await this.fetchApi.fetch(`${baseUrl}${uri}`, {
headers: {
+4
View File
@@ -203,6 +203,10 @@ export interface GetEntitiesByRefsRequest {
* declarations.
*/
fields?: EntityFieldsQuery | undefined;
/**
* If given, return only entities that match the given filter.
*/
filter?: EntityFilterQuery;
}
/**
@@ -1107,6 +1107,11 @@ export const spec = {
},
},
},
parameters: [
{
$ref: '#/components/parameters/filter',
},
],
},
},
'/entities/by-query': {
@@ -862,6 +862,8 @@ paths:
- component:default/backstage
fields:
- metadata.annotations
parameters:
- $ref: '#/components/parameters/filter'
/entities/by-query:
get:
operationId: GetEntitiesByQuery
@@ -527,7 +527,7 @@ describe('createRouter readonly disabled', () => {
const entityRef = stringifyEntityRef(entity);
entitiesCatalog.entitiesBatch.mockResolvedValue({ items: [entity] });
const response = await request(app)
.post('/entities/by-refs')
.post('/entities/by-refs?filter=kind=Component')
.set('Content-Type', 'application/json')
.send(
JSON.stringify({
@@ -540,6 +540,13 @@ describe('createRouter readonly disabled', () => {
entityRefs: [entityRef],
fields: expect.any(Function),
credentials: mockCredentials.user(),
filter: {
anyOf: [
{
allOf: [{ key: 'kind', values: ['Component'] }],
},
],
},
});
expect(response.status).toEqual(200);
expect(response.body).toEqual({ items: [entity] });
@@ -219,6 +219,7 @@ export async function createRouter(
const request = entitiesBatchRequest(req);
const response = await entitiesCatalog.entitiesBatch({
entityRefs: request.entityRefs,
filter: parseEntityFilterParams(req.query),
fields: parseEntityTransformParams(req.query, request.fields),
credentials: await httpAuth.credentials(req),
});