Load the workspace catalog at runtime
Load the logical data model (LDM) of a workspace at runtime when your users choose what to visualize, or when you don’t know the model at build time. If the model is fixed, generate constants instead; see Export catalog.
Before you start
You need an IAnalyticalBackend and a workspace identifier. Inside a React tree wrapped in BackendProvider and WorkspaceProvider, get both from useBackendStrict and useWorkspaceStrict.
Load the catalog
Ask the workspace for its catalog, restrict what to load, and call load().
import { type IAnalyticalBackend, type IWorkspaceCatalog } from "@gooddata/sdk-backend-spi";
export function loadCatalog(
backend: IAnalyticalBackend,
workspace: string,
signal?: AbortSignal,
): Promise<IWorkspaceCatalog> {
let factory = backend
.workspace(workspace)
.catalog()
.forTypes(["measure", "attribute", "dateDataset"])
.withGroups(false);
if (signal) {
factory = factory.withSignal(signal);
}
return factory.load();
}
| Option | Effect |
|---|---|
forTypes(types) | Load only these item types: "measure", "attribute", "fact", "dateDataset", "attributeHierarchy" (see Attribute hierarchies). Loading less is faster. |
withGroups(false) | Skip loading catalog groups when you do not show them. |
includeTags(refs), excludeTags(refs) | Keep or drop items by tag. |
forDataset(ref) | Limit items to one dataset. |
withSignal(signal) | Cancel the request through an AbortSignal. |
Wrap it in a hook
useCancelablePromise handles loading, error, and cancellation when the backend or workspace changes. It calls
your factory with an AbortSignal. Pass it to withSignal, so that switching workspaces aborts the request still in
flight instead of letting it finish in the background.
import { useBackendStrict, useCancelablePromise, useWorkspaceStrict } from "@gooddata/sdk-ui";
export function useWorkspaceCatalog() {
const backend = useBackendStrict();
const workspace = useWorkspaceStrict();
return useCancelablePromise(
{ promise: (signal) => loadCatalog(backend, workspace, signal) },
[backend, workspace],
);
}
export function CatalogSummary() {
const { status, result: catalog } = useWorkspaceCatalog();
if (status !== "success") {
return <div>{status === "error" ? "Could not load the catalog" : "Loading catalog..."}</div>;
}
return <div>{catalog.measures().length} measures</div>;
}
Load the catalog once, high in the component tree, and pass it down through props or a context. A catalog can hold thousands of items, and each load() is a round trip to the analytics engine.
Read the items
Each catalog item wraps a metadata object with id, ref, title, description, and optional tags.
| Item | Key fields |
|---|---|
ICatalogMeasure | measure.ref, measure.id, measure.title, measure.tags |
ICatalogAttribute | attribute.ref, attribute.title, defaultDisplayForm.ref, displayForms[] |
ICatalogDateDataset | dataSet.ref, dateAttributes[].defaultDisplayForm.ref, dateAttributes[].granularity |
An attribute has several display forms. Offer the default one and keep the others for a label switcher:
import { type IWorkspaceCatalog } from "@gooddata/sdk-backend-spi";
export function attributeOptions(catalog: IWorkspaceCatalog) {
return catalog.attributes().map((item) => ({
id: item.attribute.id,
title: item.attribute.title,
displayForm: item.defaultDisplayForm.ref,
otherDisplayForms: item.displayForms.map((displayForm) => displayForm.ref),
}));
}
Turn items into executable objects
Visual components take IMeasure and IAttribute, not catalog items. Build them from the references.
import { newAttribute, newMeasure, type ICatalogAttribute, type ICatalogMeasure } from "@gooddata/sdk-model";
import { ColumnChart } from "@gooddata/sdk-ui-charts";
export function PickedChart({ measure, attribute }: { measure: ICatalogMeasure; attribute: ICatalogAttribute }) {
return (
<ColumnChart
measures={[newMeasure(measure.measure.ref)]}
viewBy={newAttribute(attribute.defaultDisplayForm.ref)}
/>
);
}
Offer only compatible items
After a user picks a measure, offer only the attributes that can slice it. The catalog computes that list for you.
import { type IWorkspaceCatalog } from "@gooddata/sdk-backend-spi";
import { newMeasure, type ICatalogMeasure } from "@gooddata/sdk-model";
export async function attributesFor(catalog: IWorkspaceCatalog, measure: ICatalogMeasure) {
const available = await catalog
.availableItems()
.forItems([newMeasure(measure.measure.ref)])
.load();
return available.availableAttributes();
}
availableItems() also accepts forInsight(insight) to check compatibility with a whole visualization.
Notes
- Titles come back in the locale of the user making the request. Reload the catalog when the locale changes.
tagsis optional on every metadata object. Default it to an empty array before you filter on it.- The catalog reflects the model at load time. Reload after your application changes the model.
- To index items by
ObjRef, key withserializeObjRef; see Working with object references.
Related
Install and configure @gooddata/catalog-export to generate JavaScript or TypeScript constants for the Logical Data Model objects in a workspace.
Create simple measures with newMeasure, arithmetic measures from two operands with newArithmeticMeasure, and inline MAQL measures with newInlineMeasure.
Create and modify IAttribute objects with newAttribute, apply optional local identifiers and alias overrides.
Compare, key, narrow, and print ObjRef values with areObjRefsEqual, serializeObjRef, and the type guards instead of reading identifier fields by hand.
Read attribute hierarchies from the workspace catalog, and list them from a dashboard plugin.