Write an action

Actions are payloads of information that identify the state of your application. Actions, which are JavaScript objects, use a type property that indicates the type of action it performs, such as a subscription, get state, or a process input.

When your widget is displaying its initial data you may want to configure a button that invokes an action that generates data. When you invoke an action, you specify the type of action so that the system knows what to do. You may also choose to include additional information. The system takes that action and invokes an endpoint in the REST API. It does this using Redux-Saga, which enables asynchronous calls. Once the endpoint is invoked, the system takes its response and places it into a specific part of the Redux store. Selectors that listen to that part of the Redux store (using the connect elements described earlier) will be updated to reflect the new data.

Actions return promises, which represent the eventual completion of an operation and its resulting value. Promises are either resolved, where no exception occurs, or rejected, where an exception occurs. Resolved actions are identified by the OK status of the response. Once an action is either resolved or rejected, it is completed.

Actions do not describe how the application state changes, however they do use reducers, which specify how an application’s state changes in response to actions that are sent to the state tree. A reducer is a pure function that takes the previous state and an action and returns the next state. OSF provides several default actions, which are found in the @oracle-cx-commerce/actions/<action_type> directory, that contain information that sends data to an application. Information is also sent to and from a state tree for your application. You can use default actions to perform such tasks as displaying product information or profile addresses, retrieving inventory and adding or removing shipping group information.

When you create your own action, it should be stored in your /plugins/actions/<action_type> directory.

The following example of a /plugin/actions/get-currency/meta.js file creates the get-currency action. The metadata for this action specifies an endpoint property, which is required to associate this action with an endpoint:

/**
 * Metadata for the _getCurrency action.
 */
 export const _getCurrency = {

   // This action uses a Saga to invoke the _getCurrency endpoint.
   endpoints: ['_getCurrency']
};
The action /plugin/actions/get-currency/index.js file contains a saga:
import {endpointSaga, takeLatest} from '@oracle-cx-commerce/store/utils';
 /**
 * The getCurrency action.
 *
 * This exports an object with a generator function named "saga", whose presence
 * signals OSF to pass the generator function to Redux-Saga's middleware.run API
 * the first time the action is dispatched via the store API.
 *
 * The generator function results in an asynchronous endpoint invocation
 * when the action is dispatched.
 */

 export default {
   *saga() {
     yield takeLatest('_getCurrency', endpointSaga);
   }
 };

When you create an action that exports an object with a generator function, whose name is saga, the system adds it to the saga middleware to execute an endpoint. This means that when the action is dispatched, the get-currency endpoint will be asynchronously executed.

Sagas use the takeEvery and takeLatest functions. The takeEvery function allows multiple instances to be started concurrently. The takeLatest function allows only the latest request fired (displaying the latest version of data). It only allows one task to run at any moment.

Once you have created your actions, you must add them to the /plugins/actions/index.js and meta.js files. The following is an example of an index.js file:
/**
 * This module exports references that enable the application's
 * actions to be accessed using dynamic imports.
 */
 // By default, all available actions are exported.
 export * from '@oracle-cx-commerce/actions';
 // Export a reference to our getCurrency action.
 export const getCurrency = () => import('./get-currency');
The following is an example of the /plugins/actions/meta.js file:
/**
 * This module exports references to metadata for the application's actions.
 */
 export * from '@oracle-cx-commerce/actions/meta';
 export {getCurrency} from './get-currency/meta';

To invoke an endpoint response from the _getCurrency action, you must create an endpoint adapter similar to the one you created in the CREATE AN ENDPOINT section.

To do this, create a /get-currency subdirectory in your application's /src/plugins/endpoints directory. Within this directory, create an index.js file similar to the following:
import {createEndpoint, getBodyAsJson} from '@oracle-cx-commerce/wapi/endpoint';
import {populateError} from '@oracle-cx-commerce/wapi/utils';
 
/**
 * Adapter for the _getCurrency endpoint.
 */
export default createEndpoint('getCurrency', {
  /**
   * Perform any necessary extra processing on the payload object that is
   * included when dispatching an action that invokes this endpoint.
   *
   * @param {object} payload The action payload
   *
   * @return {object} Object with extra info to be included with endpoint request
   */
  processInput({repositoryId}) {
    // Append to the REST resource URL the repository id of the requested
    // currency object, and include a query parameter that limits the set
    // of returned property values.
    return {
      params: [repositoryId],
      query: {fields: 'currencyCode,displayName'}
    };
  },
 
  /**
   * Convert the response from the endpoint invocation into an object
   * to be merged into the application state.
   *
   * @param {object} response The response from the endpoint call
   *
   * @return {object} An object to be merged into the application state
   */
  async processOutput(response) {
    const json = await getBodyAsJson(response);
    // Store the returned currency info under myRepository.currencyInfo.selectedCurrency.
 
    return response.ok
      ? {
          myRepository: {
            currencyInfo: {
              selectedCurrency: json
            }
          }
        }
      : populateError(response, json);
  }
});
Once you have created the index.js file, create the meta.js file:
/**
 * Metadata for the _getCurrency endpoint.
 */
export const _getCurrency = {};
Once you have created these files, you must add an endpoint adapter to your application. To do this, edit the src/plugins/endpoints/index.js and meta.js files. The following is an example of the index.js file:
/**
 * This module exports references that enable the application's
 * endpoints to be accessed using dynamic imports.
 */
 
// By default, all available endpoints are exported.
export * from '@oracle-cx-commerce/endpoints';
 
// Export references to our own endpoints.
export const _getCurrency = () => import('./get-currency');
export const _listCurrencies = () => import('./list-currencies');
The following is an example of the meta.js file:
/**
 * This module exports references to metadata for the application's endpoints.
 */
export * from '@oracle-cx-commerce/endpoints/meta';
export {_getCurrency} from './get-currency/meta';
export {_listCurrencies} from './list-currencies/meta';