RSM: A super practical multi-scenario request management solution
Tags: javascript, vue, axios, fetch
Published: 2022-09-05 08:11:49

Front-end ers, do you feel that it is inappropriate to use the interface request that you are familiar with for so long? ? ? You may think that there is something wrong with this, if you don't just `axios.get`, `fetch`, the request will be sent, and then process the returned data, and you're done. Is it really that simple? The question is, can it really be done in a unified way for the request requirements in different scenarios? Let's talk about requests!

## Talk about the scene of the front-end request
Let's talk about the various scenarios of front-end requests first. The following are some high-frequency scenarios encountered when making requests.
1. When to send a request, is it triggered when you enter the page, or when you click a button, or when a certain data changes, or...?
2. Do you want to display the request status on the page?
3. Whether a request should be encapsulated into a function for repeated calls, such as page turning requests;
4. Are data caches for interfaces that users may request frequently, such as data that will be repeatedly viewed within a few seconds?
5. After processing some data, it is necessary to operate data across pages or modules. How to do it more conveniently? Can't all be placed in the global state;
6. Can I still submit data safely when I am offline? For example, the editor needs to automatically save drafts frequently and what should I do if I am suddenly offline?
7. Other request scenarios...

These request scenarios need to be handled differently in different projects or in different locations of the same project. If we simply use the request library to initiate requests, it will lose performance and elegance.

## Manage request scenarios

Because of the above problems, there is a concept called Request scene management (RSM, Request scene management). Let's talk about this concept. First, the picture above.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5faml7the10jwzsmnnvr.png)

Like the Flux concept, it just proposes a set of process specifications, and then each developer can refer to it and transform it to form their own unique ideas, and then code to implement it.

My understanding is that it's more like putting a robotic arm, a paint bucket or something on the request library, arming the request library, like Iron Man.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8pufpi2v3v0hezvo4r9.png)

Here, this specification proposes 4 processes, which are as follows:
### request timing
Describe when a request needs to be made.

- Initialize display data, such as just entering an interface or sub-interface;
- Human-computer interaction triggers CS interaction, which requires changing data to re-issue requests, such as page turning, filtering, sorting, fuzzy search, etc.;
- Pre-loading data, such as pre-loading the content of the next page in a pagination, predicting that the user clicks a button to pre-fetch data;
- To operate server-side data, it is necessary to issue a request for addition, deletion and modification, such as submitting data, deleting data, etc.;
- Synchronize the status of the server, such as polling requests in scenarios where data changes rapidly, and re-pulling data after operating a certain data;

### Request behavior

Describes how to handle the request.

- Placeholder request, displaying loading, skeleton diagram, or the last real data used when requesting;
- Cache high-frequency responses, and execute requests multiple times will use fresh data;
- Multi-request serial and parallel;
- Anti-shake for frequent requests, avoid front-end data flashing, and reduce server pressure;
- Important interface retry mechanism to reduce the probability of request failure caused by network instability;
- Silent submission, when you only care about submitting data, directly respond to the success event after submitting the request, and the background ensures that the request is successful;
- Offline submission, temporarily store the submitted data locally when offline, and submit it after network connection;

### request event

Indicates that the request is sent with the request parameters and the response is obtained. This is the most commonly used `axios`, `fetch`, `XMLHttpRequest`, etc. Look! Here we have to re-understand the positioning of the above request schemes, which is only one of the links in the management of request scenarios.

### Response data management

As the name implies, it is to manage the response data in a unified manner, and the response data can be operated at any location. This part is basically used in combination with the state mechanism of the MVVM framework such as `react` and `vue`, as if there is a special purpose to manage the response data. `redux`, `vuex`, you can manipulate these stateful response data across modules without any event mechanism.

- Remove the cached response data and pull it from the server when the request is made again;
- Update cache response data, which can update response data at any location, which is very beneficial to update data across pages;
- Refresh the response data, which can re-refresh the response data at any location, and is also very beneficial to update data across pages;
- Custom setting cache, when requesting batch data, you can manually set the cache for batch data one by one, so as to satisfy the cache hit of subsequent single data;

## alova, an RSM implementation library

`alova` is a relatively easy-to-use RSM implementation library I found, because its design is really like `axios`, and it can be used by novices quickly, and it can also cooperate with any request library.

Let’s briefly demonstrate the use of `alova`, and finally start to practice the code. Before using `alova`, you need to create an instance, assuming we use it in the vue project.
```javascript
import { createAlova } from 'alova';
import VueHook from 'alova/vue';
import GlobalFetch from 'alova';

const alovaInstance = createAlova({
    // request interface prefix
    baseURL: 'https://api.alovajs.org',
    
    // Used to create stateful response data for the mvvm library
    // The vue project passes in VueHook, and the react project passes in ReactHook
    statesHook: VueHook,
    
    // Pass a request adapter, GlobalFetch is the fetch api adapter we provide
    // You can also customize an adapter if you want to use axios
    requestAdapter: GlobalFetch(),
    
    // Does it smell familiar?
    beforeRequest(config) {
        config.headers.token = 'tokenxxx';
    },
    async responsed(response) {
      const json = await response.json();
      if (json.code !== 200) {
        throw new Error(json.message);
      }
      return json.data;
    },
});
```

### Take Todo as an example, initiate a todo details request
```javascript
// First define a request function, which returns a request object, which represents the information of a request, but does not actually issue a request
// its usage is very close to axios
const getTodoDetail = id => alovaInstance. Get('/todo', {
    params: {
        id
    },
    
    // The local cache is 50000 milliseconds, and the cache will be hit when the request is made again, and the request will not be issued again
    localCache: 50000,
});

// initiate a request
const {
    // loading is the loading state value, when it is loaded, its value is true, and it is automatically updated to false after the end
    // In the Vue3 environment, it is a value of type Ref, you can access it through loading.value, or directly bind to the interface
    loading,
    

    // stateful response data
    data: todoDetail,

    // Request error object, it has a value when the request is wrong, otherwise it is undefined
    error,

    // successful callback binding
    onSuccess,

    // Failed callback binding
    onError,

    // complete callback binding
    onComplete,
    
} = useRequest(getTodoDetail(this.$params.todoId)); // Send the request by passing in the request object
onSuccess(todoListRaw => {
  console.log('The request is successful, the response data can also be accessed here:', todoListRaw);
});
onError(error => {
  console.log('The request failed, the error message is:', error);
});
onComplete(() => {
  console.log('The request is completed, it will be called regardless of success or failure');
});
```

You can directly use the state returned by `useRequest` to bind to the interface

```html
<div v-if="loading">Loading...</div>
<div v-else-if="error" class="error">{{ error.message }}</div>
<template v-else>
    <div class="todo-title">{{ todoDetail.title }}</div>
    <div class="todo-time">{{ todoDetail.time }}</div>
</template>
```

### submit data
```javascript
// Create a request object for submitting data
const createTodo = newTodo => alovaInstance.Post('/create-todo', newTodo);

const {
    loading,
    data,
    error,

    // The function of the manual sender request, the request is sent after the call
    send: addTodo,
} = useRequest(newTodo => createTodoPoster(newTodo), {
    // When immediate is false, it is not emitted by default
    immediate: false
});

// assume this is the data we need to submit
const newTodo = {
    title: 'New todo item',
    time: new Date().toLocaleString()
};

// Used to refresh the todo list data after successful submission
const { fetch } = useFetcher(alovaInstance);

// Manually send the request
const handleAddTodo = async() => {
    try {
        cost result = await addTodo(newTodo);
        console.log('Add todo item successfully, the response data is:', result);
        
        // You may need to refresh the todo list data after the submission is successful, you can call the fetch function here
        fetch(getTodoList());
    } catch(error) {
        console.log('Failed to add todo item, the error message is:', error);
    }
};
```
Click the button in the interface to initiate the request
```html
<!-- Ignore other... -->
<button @click="handleAddTodo">Create todo</button>
```

## Finally
Because of the space, today's sharing will come here first. Here, it only demonstrates a little bit of alova's functions. Its power is more than that. It also gives us a lot of practical request processing solutions, whether it is in the project. It is very helpful to improve performance, improve code superiority, or reduce server pressure. Interested partners can go to github to learn more about it!

Guys, do you think there are any other examples of request scenarios?