1.0.8 • Published 2 years ago

wxess-axios v1.0.8

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

wxess-axios

this is a request library based on axios secondary encapsulation

Don't know axios?

please check the official documents of axios => click me

Packaging Characteristics

Features

  • Support most features of axios
  • Quickly realize basic requirements by configuration
  • Better support for typescript
  • More suitable for business projects

Installing

Using npm:

$ npm install wxess-axios -S

Basic usage

// Create an axios instance
import { createAxios } from 'wxess-axios';
const axios = createAxios({
    // host api
    baseURL: 'http://xxx',
    headers: {
        'content-type': 'application/json'
    }
});

// Request API definition
const handleLogin = (data) => {
    return axios.createRequest({
        url: '/api/login',
        method: 'post',
        data
    });
};

// Using APIs
const params = {
    username: 'xxx',
    password: 'xxx'
};
const clickHandle = async () => {
    if(params.username !== '' && params.password !== '') {
        const result = await handleLogin(params);
        console.log(result); // response result
    }
};

Create instance configuration

Instance options will inherit the Public configuration

    const axios = createAxios({
        // Host api (Required) 
        baseURL: string;
        // Run in build environment? (Optional)
        // If the value is true, some internal warnings will be ignored
        // The default value is false
        isPro: boolean;
        // You can continue to add public configuration or Axios configuration below
        ...others
    });

Request apis configuration

Request apis configuration also inherits the Public configuration

    const promise = axios.createRequest({
        // Whether to ignore instance interceptors and request API interceptors
        // The default value is false
        isIgnoreInterceptor: boolean;
        // You can continue to add public configuration or Axios configuration below
        ...others
    });

Public configuration

Public configuration will eventually inherit Axios configuration

    {
        // Can I cancel the request manually?
        // The default value is false
        isCancelRequest: boolean;
        // Whether to convert form data into URL parameters when submitting it in JSON
        // Note: the content type of the request must be 'post' or 'put'
        // The default value is true
        isToURL: boolean;
        // How the interceptor works?
        // The default value is `auto`
        pattern: 'cover' | 'no-repeat' | 'add' | 'auto';
        // Specify the keys of the interceptor to be used
        interceptors: {
             request?: string[];
             response?: string[];
             errorRequest?: string[];
             errorResponse?: string[];
             common?: string[];
        }
    }

Define interceptors

There are five types, namely: request, response, errorRequest, errorResponse, common

The following example will introduce the request interceptor

    // define
    const reqInter = {
        carryToken: (params) => {
            const { requestData, isPass, config, ...others } = params;
            /* When 'isPass' is' true', the returned parameters 
               will be passed to the next interceptor */
            /* otherwise the interceptor will be aborted, Then return
               'responsedata' to Axios for internal processing */
            return {
                // Axios request configuration
                requestData,
                // Continue to call the interceptor?
                isPass,
                // Combined configuration of instance configuration and 
                // request API configuration
                config,
                // Custom passed parameters
                ...others
            }
        },
        openLoading: (params) => {
            return params;
        }
    };
    // register or remove
    axios.registerInterceptors('request', reqInter);
    axios.unRegisterIntercetors('request', ['carryToken']);
    // First usage(low priority)
    const axios = createAxios({
        interceptors: {
            request: ['carryToken']
        }
    });
    // Second usage (higher priority)
    const promise = createRequest({
        interceptors: {
            request: ['openLoading']
        }
    });

NOTE: The pattern option of public configuration will affect the merging rules of interceptors

How to support typescript

    // Get type prompt when using request API
    // Generally, the client and server will agree on this format
    type ResponseResult = {
        msg: string;
        status: number;
        data: {
            response: void; // Special attention should be paid here
            tips: string;
            code: number;
            ...
        }
    };
    // Get type prompt when configuring interceptor
    import { ReqInterceptorParams } from 'wxess-axios';
    const reqInter = {
        handleRequest({ requestData, isPass, config }: ReqInterceptorParams) {
            // Processing business
            return {
               requestData, isPass, config
            }
        }
    };
    type InterceptorKeys = {
        request: (keyof typeof reqInter)[],
        response: [],
        errorRequest: [],
        errorResponse: []
    }
    // Injection InterceptorKeys and ResponseResult
    const axios = createAxios<ResponseResult, InterceptorKeys>({
        baseURL: 'xxxx'
    });
    // Use cases
    interface LoginParams = {
        username: string;
        password: string;
    }
    const handleLogin = async (data: LoginParams) => {
        // The type here will replace the 'void' in the 'responseResult' type`
        type LoginResult = {
            uid: string;
            username: string;
        };
        return axios.createRequest<LoginResult>({
            url: '/api/login',
            method: 'post',
            data
        });
    }
    const result = await handleLogin({
        username: 'xxx',
        password: 'xxx'
    });
    // The result here has the type prompt
    console.log(result);

NOTE: The response interceptor must be used to return the specified response type

You can also customize the processing of response data at the front end

Of course, if the client and server can directly return the specified type of data, there is no need to process it

    import { ResInterceptorParams } from 'wxess-axios';
    const resInter = {
        // The following case uses the server built by koa router
        handleResponseData({ responseData, ...others }: ResInterceptorParams) {
            const { status, statusText, data } = responseData;
            return {
                // The data here will be passed to the interceptor later, 
                // and finally returned to the business API
                responseData: {
                    msg: statusText,
                    status,
                    data
                },
                ...others
            }
        }
    };
    // Don't forget to register
    axios.registerInterceptors('response', ['handleResponseData']);
    // Don't forget to configure
    const axios = createAxios<ResponseResult, InterceptorKeys>({
        baseURL: 'xxxx',
        interceptors: {
            response: ['handleResponseData']
        }
    });

Business requirements

Here we will introduce some common business requirements

Carry token

    import { createAxios, ReqInterceptorParams } from 'wxess-axios';
    // define
    const reqInter = {
        carryToken: ({ config, isPass, ...others }: ReqInterceptorParams) => {
            const token = localStorage.getItem('pc-user-token');
            if (token) {
                config.headers!.Authorization = token;
            }
            return {
                config,
                ...others
            }
        }
    };
    // to configure
    const axios = createAxios({
        interceptors: {
            request: ['carryToken']
        }
    });
    // register
    axios.registerInterceptors('request', ['carryToken']);
    

Global request animation

Here, take vue3 +element plus as an example

Define the display state of the animation

    import { reactive, toRefs } from 'vue';
    // Expose hook
    export function useLoading() {
        const status = reactive({
            isLoading: false,
            size: 0
        });
        return {
            ...toRefs(status),
            setLoading: createStatus(status, 'isLoading'),
            addSize: createStatusByAdd(status, 'size')
        };
    }
    // Modify the display status
    function createStatus(status, key) {
        return (value) => {
            return status[key] = value;
        };
    }
    // Record the number of multiple concurrent requests
    function createStatusByAdd(status, key) {
        return (value) => {
            return status[key] += value;
        };
    }

UI control of loading animation

    import { watch } from 'vue';
    import { ElLoading } from 'element-plus';
    import { useLoading } from 'xxx';
    const { isLoading, setLoading, addSize } = useLoading();
    // `element-plus` loading instance
    let loadingInstance = null;
    // Delay execution timer
    let loaderTimer = null;

    watch(isLoading, (nValue) => {
        if (nValue) {
            // After the server returns the result within 300ms 
            // Global animation is not displayed
            loaderTimer = setTimeout(() => {
                loadingInstance = ElLoading.service({
                    lock: true,
                    text: 'loading...',
                    background: 'rgba(0, 0, 0, 0.6)',
                });
            }, 300);
        } else {
            if (loadingInstance) {
                loadingInstance.close();
            }
            clearTimeout(loaderTimer);
        }
    });
    // You can use this function in the interceptor to control 
    // the state of the loading animation
    export function alterLoadingStatus(isRequest) {
        if (addSize(0) === 0) {
            setLoading(true);
        }
        isRequest ? addSize(1) : addSize(-1);
        if (addSize(0) === 0) {
            setLoading(false);
        }
    }

Associate the feature loaded with animation with the interceptor of axios

    import { alterLoadingStatus } from 'xxx';
    import { CommonInterceptorParams } from 'wxess-axios';
    // Define common interceptor
    const commonInter = {
        loadingAnimation: (config: CommonInterceptorParams) => {
            const { interType } = config;
            if (interType === 'request') {
                alterLoadingStatus(true);
            } else {
                alterLoadingStatus(false);
            }
            return config;
        }
    };
    // to configure
    const axios = createAxios({
        interceptors: {
            request: ['loadingAnimation']
        }
    });
    // register
    axios.registerInterceptors('common', commonInter);

NOTE: If other interceptors conflict with the key of the common interceptor, the common interceptor will be ignored

Processing error statusCode

    import { AxiosErrorType, ResErrorInterceptorParams } from 'wxess-axios';
    const resErrorInter = {
        responseStatusCode({ error, ...others }: ResErrorInterceptorParams) {
            let errorMsg = 'unknown error';
            if (error) {
                const { name, code, request, response } = error;
                if (name === 'AxiosError') {
                    switch (code) {
                        // Client error
                        case AxiosErrorType.evreq:
                            // You can handle client errors here => Status code 4xx
                            break;
                        // Server error
                        case AxiosErrorType.ebres:
                            // You can handle server errors here => Status code 5xx
                            break;
                        // others
                    }
                } else if (name === 'CanceledError') {
                    errorMsg = 'The request has been `cancelToken.cancel ` cancelled!'
                }
                error.message = errorMsg;
            }
            return {
                error,
                ...others
            }
        }
    };

Before creating a response error handler, you should specify which status codes will be processed by response or errorResponse interceptor

    const axios = createAxios({
        // default value
        validateStatus(code) {
            return code >= 200 && code < 300;
        },
        interceptors: {
            errorResponse: ['responseStatusCode']
        }
    });
    axios.registerInterceptors('errorResponse', resErrorInter);

Cancel request

    const handleLogin = (data) => {
        const handler = axios.createRequest({
            url: '/api/login',
            method: 'post',
            data,
            // This parameter must be specified to cancel the request
            isCancelRequest: true
        });
    };
    // Execute the cancellation request at the appropriate time
    axios.cancelRequest('All requests on the instance have been canceled!');

How to organize your code

Will be available in the next version

License

MIT

1.0.8

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.0

2 years ago