Fluent Commerce Logo
Sign In

Display REST API Data in Standard Library Components

How-to Guide
Extend

Author:

Lesley Dean

Changed on:

8 July 2024

Key Points

  • For Frontend (React) Developers who are familiar with using the Fluent OMX Component SDK
  • Build a REST API Data Provider Component to enable the standard Component Library to render data from the Fluent Platform REST APIs
  • Learn how to override the data provided to components
  • Learn how to support template value props for dynamic input
  • Learn how to decorate the query results for enabling `byName` attributes access in the manifest

Steps

Introduction

Step arrow right iconOverview

The Fluent UX Framework provides a Component Library for quickly configuring Fluent web apps.

Currently these Components receive data from the Page Query, which is . The Fluent Platform includes a number of REST APIs, not available via . This means that the standard Components can't display REST based data.

Imagine if you could easily use the UX Framework Component Library to build and extend screens with data from these APIs?

This will guide you through implementing a custom data provider component that makes it possible to display REST based data in the standard UX Framework Component Library.

Problem Statement & Scenario

Step arrow right iconProblem Statement

Since the standard Components accept datasources from the page query defined in the , the only way to display data from REST APIs is to write custom components using the Component SDK.

This would need to be done for each component where a custom data source is required, and potentially adds significant effort to implementation.

While the Component SDK provides the tools to achieve this, it would be ideal if we could reuse the existing component library, and configure an alternate data source in the .

Step arrow right iconScenario

Imagine you needed to provide an enhanced Activity Viewer, Webhooks Dashboard, or display information from the API on your Orders Dashboard.

Additionally, you need to achieve this while maintaining a consistent look, feel, and configuration experience, while minimising the total cost of custom code components?

What if this could be achieved with one simple custom component, and work for all components in the library?

No alt provided

An example Dashboard using Event API as a datasource for the standard Dashboard Tile Component

Solution

Step arrow right iconApproach

Following the pattern of the default page component, let's decouple the data fetching and display logic so that we can use the standard cards, lists, and other library components.

Let's write a simple custom component as a configurable data provider for nested components to use.

In this approach, the data provider component could accept an `endpoint`, and some additional `props` to configure the request or body parameters. Internally, it would execute the REST Call, and return a data source for the nested components defined within the .

Example usage:

1{
2  "component": "devrel.provider.rest",
3  "props": {
4    "endpoint": "api/v4.1/event",
5    "props": {
6      "context.entityType": "ORDER",
7      "eventType": "ORCHESTRATION",
8      "eventStatus": "FAILED",
9      "from": "{{dateStringFormatter (dateAdd hours=-24) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}"
10    }
11  },
12  "descendants": [
13    /* display components here... */
14  ]
15}

Implementation Steps

Step arrow right iconStep 1: Create a custom Data Provider Component

Using the Component SDK, create a new file in the components folder called `RestProvider.tsx`.

Create a new Interface to accept the RestProviderProps:

1export interface RestProviderProps {
2  data: any;
3  endpoint: string;
4  props: Record<string, string>;
5}

The `data` field will automatically be provided by the UX Framework and contain the Page Query Data.

The `endpoint` and `props` fields will be configured in the .

Now you can create the Component:

1export const RestProvider: FC<RestProviderProps> = ({
2      data,
3      endpoint,
4      props,
5    }) => {
6      // TODO: Implementation Code here...
7};

A you can see, we make use of a React Function Component (`FC`), which you should import from `react`.

Step arrow right iconStep 2: Render Props and Build the REST endpoint with props

The UX Framework provides the ability to pass page query and URL parameters into the props values. The best way to handle this is to support template strings as props, which then need to be “rendered”. The TemplateRegistry provides a render function to do this for you. So all we need to do is loop through the provided props, and call the render function.

Let’s create a separate function in the same file for this:

1const getRenderedProps = (props: Record<string, string>, data: any) => {
2  return Object.fromEntries(
3    Object.entries(props).map(([key, value]) => [
4      key,
5      TemplateRegistry.render(value, data)
6    ])
7  );
8};

You will need to import the TemplateRegistry from `mystique/registry/TemplateRegistry`.

Now we can use this function in our Component implementation and build the endpoint:

1  const [endPointWithProps] = useState(
2    () => `${endpoint}?${new URLSearchParams(getRenderedProps(props, data))}`
3  );

The `useState` hook should be imported from `react`.

As you can see from the code above, we will keep state of the provided parameters, so as not to re-render  the component unnecessarily if the props values are changing all the time. This is relevant to our example use case, where we will be providing a “Last 24 Hours” date range to the request, and this would be changing every millisecond, triggering a re-render unnecessarily.

Step arrow right iconStep 3: Call the REST API and return the result to the child components

The Component SDK provides a `useRest` hook to call the Fluent Platform REST APIs:

1const response = useRest(endPointWithProps);

Import the `useRest` hook from `mystique/hooks/useRest`.

The `response` will contain 2 simple fields, `status` and `result`. We can use the `status` to determine what to return using a switch statement.

In the that the API call is still executing, it is helpful to show the `Loading` component as helpful feedback for the user.

In the that the API an error, we can log the rendered request to the console to help developers debug the problem, and depending on the use case present something else to the UI.

When the API successfully, the status will be `ok`, and the `result` object will be populated with the REST response payload. In this case, we can then return the `Children` component, and override the data source. The result of the REST query now becomes the `data` value injected into each descendant component, so any component designed to display information can be used to show it.

Let’s implement a simple switch statement to render feedback to the user:

1switch (response.status) {
2  case "ok":
3    return <Children dataOverride={decorateQueryResult(response.result)} />;
4
5  case "loading":
6    return <Loading />;
7
8  default:
9    // includes "error"
10    console.error(
11      `Could not retrieve data from REST API: ${JSON.stringify(endPointWithProps)}\n Response: ${JSON.stringify(response, null, 2)}`
12    );
13    return <div>Error occurred loading data from REST API</div>;
14}

Import `Children` from `mystique/components/Children`, `Loading` from `mystique/components/Loading`, and `decorateQueryResult` from `'../../../lib/mystique-export'`.

Step arrow right iconStep 4: Register the Component and try it out

In the `index.tsx`, register the component:

1ComponentRegistry.register(["devrel.provider.rest"], RestProvider, {category: "content"});

You'll need to import `RestProvider` from `'./components/providers/RestProvider'`.

Start your local server by running `yarn start`, and add your local server to the plugins configuration of your Fluent OMS webapp :

1{
2    "type": "url",
3    "src": "http://localhost:3001"
4}

Since we’ll try this using the API, let’s use the Insights section of the Fluent OMS webapp. If you haven’t already, you will need to override the default Insights fragment for Fluent OMS.

Let’s add a new Page to the Insights fragment, and try out the component:

1{
2  "type": "page",
3  "path": "/devrel-events-dashboard",
4  "nav": {
5    "label": "DevRel Events Dashboard",
6    "icon": "MdEvent"
7  },
8  "component": "fc.page",
9  "props": {
10    "title": "DevRel Events Dashboard - Updated on: {{dateStringFormatter (dateAdd)}}"
11  },
12  "descendants": []
13}

To test the REST Provider Component, we’ll use the standard `fc.dashboard.threshold` component from the standard Component Library. This will need to be nested as a child descendant of the RestProvider component:

1{
2  "component": "devrel.provider.rest",
3  "props": {
4    "endpoint": "api/v4.1/event",
5    "props": {
6      "context.entityType": "ORDER",
7      "eventType": "ORCHESTRATION",
8      "eventStatus": "FAILED",
9      "from": "{{dateStringFormatter (dateAdd hours=-24) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}"
10    }
11  },
12  "descendants": [
13    {
14      "component": "fc.dashboard.threshold",
15      "props": {
16        "label": "Failed",
17        "value": "{{ results.length }}",
18        "thresholdLow": 1,
19        "thresholdHigh": 10,
20        "link": "#/events?context.entityType=ORDER&eventType=ORCHESTRATION&eventStatus=FAILED&from={{dateStringFormatter (dateAdd hours=-24) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}"
21      }
22    }
23  ]
24}

As you can see above, we’re configuring the `devrel.provider.rest` component to call the API with filter parameters to return only FAILED Events for the last 24 hours, but remember you could pass in dynamic values from a page query result based on the use case.

No alt provided

A standard Dashboard Tile Component displaying failed Order Orchestration Events

What else can you do?

Step arrow right iconThe Art of the Possible...

The applications for this include composing various UI capabilities for the data exposed by the Fluent Platform APIs. You can build out Dashboards, Dashboards (coming soon), enhanced Activity views for entities, display execution paths and status transition information, or even display a List of Workflows and a detailed Library.

Combining this with standard page queries, you can build richer domain or based dashboards, activity views, etc.

You can make further enhancements to this component, such as rendering the Loading and Error responses in a card.

Additionally, you can swap out the `useRest` hook with the `getRest` promise to query data from any other external API.

Finally, while this component won't allow support for all child component features, such as list paging and filtering, you can combine this with a custom List wrapper component, to enable these capabilities.

The REST API Data Provider demonstrates how quick and easy it is to extend the UX Framework, and maximise reuse of standard library components for REST based data.

Conclusion

Step arrow right iconWrapping up

As you can see, this little custom component makes it super simple to enable presentation of REST API based data with the standard Component Library.