Resource Concepts

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

  • Resource Templates
  • Resource Store
  • Resource Middleware

Templates

The resource template is a description that the resources uses to read, find and init data in the store. Resource templates are flexible to enable connecting resources to multiple different providers, for example RESTful APIs, client data (using an in-memory template).

Templates should be stateless so that they can be re-used across through-out an application, using the resource options to determine the data required and the resource controls to interact with the resource store, for example putting the data into the store.

Create a template using createResourceTemplate from the @dojo/framework/core/middleware/resources module.

userResourceTemplate.ts

  1. import { createResourceTemplate } from '@dojo/framework/core/middleware/resources';
  2. interface User {
  3. firsName: string;
  4. lastName: string;
  5. username: string;
  6. email: string;
  7. }
  8. // The type for the data is passed to the `createResourceTemplate` factory
  9. export default createResourceTemplate<User>({
  10. read: (request: ResourceReadRequest, controls: ResourceControls) => {
  11. // use the `request` to "fetch" the data from the data-source
  12. // and use the controls to set the data into the store.
  13. },
  14. find: (request: ResourceFindRequest, controls: ResourceControls) => {
  15. // use the controls with the request to set the found item based
  16. // on the request
  17. }
  18. });

The resource controls are injected to all the data template functions to enable working with the backing resource store. get() is used to return data from the store based on the request passed and put() is used to set data into the store for the request.

See the Resource Templates section for more details.

Store

The resource store is where all the data is stored and responsible for wiring widgets using the resource middleware with the ResourceTemplate passed to the widget. The store invalidates all widgets that have subscribed for events based on the type and details of the event as well as handling asynchronous results from the resource template. The resource store is automatically created for a template that is passed to a widget. A user never explicitly creates or works directly with the resource store.

MyWidget.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
  3. import DataAwareWidget from './DataAwareWidget';
  4. import userResourceTemplate from './userResourceTemplate';
  5. const resource = createResourceMiddleware();
  6. const factory = create({ resource });
  7. export default factory(function MyWidget({ middleware: { resource }}) {
  8. return (
  9. <div>
  10. {/* The resource store is created internally for the template passed to the widget */}
  11. <DataAwareWidget resource={resource({ template: userResourceTemplate })}>
  12. </div>
  13. );
  14. });

Middleware

The resource middleware is the interface required to work with resource templates and “resource-aware” widgets. The middleware exposes the complete API for working with resource templates.

MyResourceAwareWidget.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
  3. import FancyLoadingIndicator from './FancyLoadingIndicator';
  4. // The resource item interface
  5. interface ResourceItem {
  6. label: string;
  7. }
  8. // create the resource middleware passing the type of the resource required
  9. // passing the generic type means that the `resource` property will
  10. // be exposed on the widget's property interface
  11. const resource = createResourceMiddleware<ResourceItem>();
  12. // pass the created middleware to the `create` function
  13. const factory = create({ resource });
  14. export default factory(function MyResourceAwareWidget({ id, properties, middleware: { resource } }) {
  15. // de-structure the required resource APIs, these can also be accessed
  16. // directly from `resource`
  17. const { getOrRead, isLoading, createOptions } = resource;
  18. // get the `template` and `options` from the widgets properties
  19. // the options are optional so need to be defaulted using the
  20. // createOptions function from `resource`
  21. const {
  22. resource: { template, options = createOptions(id) }
  23. };
  24. // Call `getOrRead` to request the data based on the `template` and `options`
  25. const [items = []] = getOrRead(template, options({ page: 1, size: 20 }));
  26. // Check if the resource is current loading
  27. if (isLoading(template, options())) {
  28. // if the resource is loading return a fancy loading indicator
  29. return <FancyLoadingIndicator />;
  30. }
  31. // If the items have been loaded return them in a list
  32. return <div>{items.map((item) => <li>{item.label}</li>)}</div>;
  33. });

Please see the resource middleware for more information.