Remember to have an http request support interceptor

Recently, I want to use the full js system to write a front-end and back-end learning, and created a set of TODOList project trainers. Currently only the back-end demo has been written, and the front-end is using vue. And prepare to write it again later with react and flutter.
This project
Backend demo

premise

Framework 7, a mobile ui framework, was used when writing the practitioner project, because the animation of the framework was so good that it was chosen. But in the process of using the framework, we found that the ajax request library is very simple, so we manually encapsulated it with reference to axios to support promise and interceptor.

Hands on

Don't talk too much nonsense. Code it.
comover.js

import { Request as F7Request } from "framework7";

// Encapsulating the original request object as a Promise object
function adapter(config) {
    return new Promise(function(resolve, reject) {
        F7Request({
            url: `${config.baseUrl}${config.url}`,
            method: config.method,
            headers: config.headers,
            data: config.data,
            success(data, status, xhr) {
                resolve({
                    data: JSON.parse(data),
                    status: status,
                    config: config,
                    xhr: xhr
                });
            },
            error(xhr, status) {
                let error = new Error(
                    `Request failed with status code ${status}`
                );
                error.xhr = xhr;
                reject(error);
            }
        });
    });
}

// Send requests
function dispatchRequest(config) {
    return adapter(config).then(
        function onAdapterResolution(response) {
            return response;
        },
        function onAdapterRejection(reason) {
            return Promise.reject(reason);
        }
    );
}

export default class Comeover {
    interceptors = {};
    requestHandlers = [];
    responseHandlers = [];
    config = {};
    constructor(config = ({ baseUrl = "" } = {})) {
        const self = this;

        this.config = { ...config };

        this.interceptors = {
            request: {
                use(fulfilled, rejected) {
                    self.requestHandlers.push({
                        fulfilled,
                        rejected
                    });
                }
            },
            response: {
                use(fulfilled, rejected) {
                    self.responseHandlers.push({
                        fulfilled,
                        rejected
                    });
                }
            }
        };
        
        // Method runtime binding context in class in ES6
        this.request = this.request.bind(this);
    }
    request(config) {
        // Merge default config with config when sending requests
        let inconfig = { ...this.config, ...config };
        
        // Create Promise Chain
        let chain = [dispatchRequest, undefined];
        // Create promise objects passed in the initial Promise chain
        let promise = Promise.resolve(inconfig);
        
        // Injecting the interceptor into the Promise chain
        this.requestHandlers.forEach(interceptor => {
            chain.unshift(interceptor.fulfilled, interceptor.rejected);
        });
        this.responseHandlers.forEach(interceptor => {
            chain.push(interceptor.fulfilled, interceptor.rejected);
        });
        
        // Running Promise Chain
        while (chain.length) {
            promise = promise.then(chain.shift(), chain.shift());
        }
        
        // Returns the final promise object
        return promise;
    }
}

Use

This example uses nprograms to pretend to show the progress of the request before and after all requests

import Comeover from "./comeover";
import Np from "nprogress";

const baseUrl = process.env.NODE_ENV === "development" ? "" : /* Upline address */ "";

const comeover = new Comeover({ baseUrl });

comeover.interceptors.request.use(
    config => {
        Np.start();
        return config;
    },
    error => {
        Np.done();
        return Promise.reject(error);
    }
);
comeover.interceptors.response.use(
    response => {
        Np.done();
        return response;
    },
    error => {
        Np.done();
        return Promise.reject(error);
    }
);

export { request };

Request

comeover.request({
    url: "/api/login",
    method: "post",
    data: {
        email: this.email,
        password: this.password
    }
})
    .then(({ data }) => {
        this.$store.commit("login", { token: data.message });
        router.back();
    })
    .catch(err => {
        app.dialog.alert("ERROR Incorrect username or password", "Landing Failure");
    });

summary

You can also refer to axios to continue encapsulating separate get, post, and so on, so that the demo is not written.
The Promise chain is an array, and then puts the request interceptor in front of the real request and the responding interceptor behind the real request. Then, in the order of resolve before reject after reject, paired loops are injected into promise.then. The real request resove and reject are written in the dispatchRequest, so there is no reject in the dispatchRequest, so we need to add an undefined.
When ES6's instantiation method is used alone, this pointing will be problematic and needs to be addressed. individualization

Keywords: Javascript axios Vue React Mobile

Added by kappaluppa on Fri, 23 Aug 2019 09:17:30 +0300