I wrote before An article , sharing the methods of interface management in their own projects. The conclusion is: define interface file -- with Axios export -- call interface method. In this way, the unified management of the interface and the semantics and simplifications of the calling interface are realized.
According to the use in the project, the following problems are found to be optimized:
- The interface method object exported by withAxios is opaque to the editor, so the code prompt function is missing.
- How to ensure that the component always gets the last return information when the same method is called multiple times.
Based on the above problems, the following solutions are adopted:
- Use generic resolution of typescript.
- When calling the same method, cancel the last unfinished request. Here, use the cancel method of axios. The implementation idea is to add a ` ${name}Cancel 'method to the returned method object, save and cancel the callback of the last method, and call the cancel method at a fixed time in the next request to ensure that the current request is the only one currently. (only solutions at the axis level are provided here, and other solutions are not discussed. For example, if Redux saga is used, take latest can be used.)
Show it by code (React project):
service.ts
import { IApiItem } from '@/configs/api/declares'; import withAxios from '@/utils/withAxios'; const api: IApiItem[] = [ { name: 'getSummary', url: 'http://xx:8000/api/getSummary' }, { name: 'getDetail', url: 'http://xx:8000/api/getDetail' }, { name: 'getDetailChildren', url: 'http://xx:8000/api/getDetailChildren' }, { name: 'getCurrentUser', url: 'http://xx:8000/api/getCurrentUser' }, ]; interface IProdMonitorApi { getSummary: any; getDetail: any; getDetailChildren: any; getCurrentUser: any; } export default withAxios<IProdMonitorApi>(api);
withAxios.ts
function withAxios<T>(apiConfig: IApiItem[], usePassportOrigin: boolean = false): T { const serviceMap = {} as T; apiConfig.map(({ name, url, method = 'get', ...rest }: IApiItem) => { return (serviceMap[name] = async function(data = {}) { if (serviceMap[`${name}Cancel`] && typeof serviceMap[`${name}Cancel`] === 'function') { serviceMap[`${name}Cancel`](); } const source = axios.CancelToken.source(); serviceMap[`${name}Cancel`] = () => { source.cancel(`Last outstanding request cancelled:${name}`); }; rest.cancelToken = source.token; let key = 'params'; const apiMethod = method.toLowerCase(); if (apiMethod === 'post' || apiMethod === 'put') { key = 'data'; } let fetchUrl = url; if (url.indexOf('http') !== 0) { fetchUrl = usePassportOrigin ? NetworkUtils.passportOrigin + url : NetworkUtils.serverOrigin + url; } return axios({ method, url: fetchUrl, [key]: data, fetchName: name, ...rest, } as AxiosRequestConfig); }); }); return serviceMap; } export default withAxios;
Where an interface is required:
import Service from "./service.ts"
Service.getSummary(requestParams).then(...)
Explain:
- Although there are code prompts for using generics, there is an extra amount of coding. To maintain a method interface manually has advantages and disadvantages. I haven't found a better way through ts. Colleagues had a solution before: interface management uses the form of object, and then with axios modifies the getter of each attribute of the object, points the getter to the method wrapped by axios, and finally realizes the same calling method and code prompt in this article, but this method is a bit of hack.
- Cancel dropping the last interface ensures that the data always comes from the last request interface, but sometimes there may be problems. For example, two types of users need to be displayed on the same page: common user and admin user. The interface provided by the back end is / api/v1/user, common when the parameter type=1, and admin when the type=2. If we define this interface as a method getuse R, two requests will be sent out at the same time on this page: Service.getUser({type:1}), Service.getUser({type:2}). However, since with Axios will cancel the request of the previous same method, it is likely that one request will be cancelled. The solution is to define two methods in service: getCommonUser and getAdminUser, which will write the type directly to the url. This is also in line with our goal of semantic.