Fetch useRelatedEntities in batches

Rather than making a request per relation, filter multiple
relations in a single request.

To avoid the query string getting very large, make multiple
requests on bacthes of 100 relations.

Signed-off-by: Will Sewell <willsewell@monzo.com>
This commit is contained in:
Will Sewell
2021-05-03 12:07:48 +01:00
parent e70ec932bc
commit 81c54d1f25
2 changed files with 27 additions and 8 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
Fetch relations in batches in `useRelatedEntities`
@@ -18,6 +18,8 @@ import { useApi } from '@backstage/core';
import { useAsync } from 'react-use';
import { catalogApiRef } from '../api';
const BATCH_SIZE = 100;
export function useRelatedEntities(
entity: Entity,
{ type, kind }: { type?: string; kind?: string },
@@ -40,16 +42,28 @@ export function useRelatedEntities(
return [];
}
// TODO: This code could be more efficient if there was an endpoint in the
// backend that either returns the relations of entity (filtered by type)
// or if there is a way to perform a batch request by entity name. However,
// such an implementation would probably be better placed in the graphql API.
// Make requests in separate batches to limit query string size
// (there is a `filter` param for each relation)
const relationBatches = [];
for (let i = 0; i < relations.length; i += BATCH_SIZE) {
relationBatches.push(relations.slice(i, i + BATCH_SIZE));
}
const results = await Promise.all(
relations?.map(r => catalogApi.getEntityByName(r.target)),
relationBatches.map(batch => {
return catalogApi.getEntities({
filter: batch.map(({ target }) => {
return {
kind: target.kind,
'metadata.name': target.name,
'metadata.namespace': target.namespace,
};
}),
});
}),
);
// Skip entities that where not found, for example if a relation references
// an entity that doesn't exist.
return results.filter(e => e) as Entity[];
return results.map(r => r.items).flat();
}, [entity, type]);
return {