dojo dragon main logo

Resource Concepts

Dojo resources is designed to provide a cohesive and consistent mechanism for working with data within a Dojo application. There are 2 core concepts for Dojo Resources:

  • Resource Templates
  • Resource Middleware

Templates

The resource template is a description that the resource uses work with the resource data. Resource templates are flexible enough to enable connecting resources to multiple different providers, such as RESTful APIs or client data.

Templates should be stateless so they can be re-used throughout an application by using the resource options to determine the data required and the resource controls to interact with the resource store, such as putting the data into the store.

Templates are created using the createResourceTemplate factory from the @dojo/framework/core/middleware/resources module. The API of a resource template is flexible and can be defined when creating the template, however by default the API requires a single read function that is intended to receive requests and store the resource data using the template controls.

userResourceTemplate.ts

import { createResourceTemplate } from '@dojo/framework/core/middleware/resources';

interface User {
	firsName: string;
	lastName: string;
	username: string;
	email: string;
}

// The type for the data is passed to the `createResourceTemplate` factory
export default createResourceTemplate<User>({
	idKey: 'email', // This indicates that email is the unique key of the resource
	read: (request, controls) => {
		// use the `request` to "fetch" the data from the data-source
		// and use the controls to set the data in the resource
	}
});

The resource controls are injected to all the data template functions to enable working with the backing resource store. The controls contains a put function that is used to set data in the resource based on the request.

Middleware

The resource middleware is the interface required to work with resource templates and "resource-aware" widgets. The middleware exposes a an API that can be used to work with templates within a widget in a consistent and predictable way.

MyResourceAwareWidget.tsx

import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';

import FancyLoadingIndicator from './FancyLoadingIndicator';

// The resource item interface
interface ResourceItem {
	label: string;
}

// create the resource middleware passing the type of the resource required
// passing the generic type means that the `resource` property will
// be exposed on the widget's property interface
const resource = createResourceMiddleware<ResourceItem>();

// pass the created middleware to the `create` function
const factory = create({ resource });

export default factory(function MyResourceAwareWidget({ id, properties, middleware: { resource } }) {
	// get the `template` and `options` from the widgets properties the options are optional so need to be defaulted using the
	// createOptions function from `resource`
	const {
		resource: { template, options = resource.createOptions((curr, next) => ({ ...curr, ...next })) }
	} = properties();

	// de-structure the required resource APIs, these can also be accessed
	// directly from `resource`
	const {
		get,
		template: { read }
	} = resource.template(template);

	// Call `get` with the `read` API to request the data based on the `options`
	// passing the `meta: true` option to get meta information including the loading
	// state.
	const {
		data,
		meta: { status }
	} = get(options({ page: 1, size: 20 }), { read, meta: true });
	// Check if the resource is current loading
	if (status === 'reading') {
		// if the resource is loading return a fancy loading indicator
		return <FancyLoadingIndicator />;
	}
	// If the items have been loaded return them in a list
	return <div>{items.map(({ item }) => <li>{item.label}</li>)}</div>;
});