Logic design

Recently, JD encountered an interesting problem when developing its own IDE. Due to the uniqueness of the IOT-oriented project, part of the interfaces are customized for different Party A, so the functions required by Party A are naturally different, and the interfaces provided by Party A (such as encryption sign and token signature) are naturally different. The previous method of == “request root encapsulation + interface list” == cannot meet its flexible requirements, and is also not enough to deal with the situation of single project and multiple delivery parallel. Therefore, we redesigned the black box encapsulation method for network requests for this kind of problem, which can be used in Vue, React or Node environment.

First of all, let’s identify what we want to achieve: The whole project about network part should become a configuration type, and a party a corresponds to a configuration file, configuration files need to be able to direct configuration or handle different baseURL, headers and other customized services, besides should also be able to support backward compatibility old projects, and to leave the common interface encapsulation mode, maintain readability and almost don’t need to study the cost

Common interface encapsulation methods are as follows

Export async function getTest(params) {// const res = await request < ResponseParam bb0 ({url: '/getInfo/test', method: 'POST', data: params, }); return res; }

File structure

The designed file structure is roughly as follows

src - | ... | config | - serve. Ts core (serve) | - serve | - a.t s (a) party a (party b) | | - b.t s... |...

According to this design, if a new Party A needs to deliver later, it only needs to add a file in the config/serve folder, which will not affect other deliveries and is convenient for unified configuration.


Serve core package

To help explain the logic of the code and the many points involved, I will explain in detail how it is encapsulated in this chapter, which you can read as you scroll through the UML diagrams in the next chapter (explained below in the code).

serve.ts

import request from '.. /xxxxxxx/request'; Const DefaultConf = {platform: 'default', configuration: } /** These two interfaces should be written on the outside, */ interface magicType {base_url: {release: string, dev: string, test: string,}, _header: { sign: Function, // ... } } interface encType { platform: string, configuration: string } class ServeCore { platform: string; // platform identifier request: any; [prop: string]: any; constructor(ENC:encType = defaultConfig) { this.platform = ENC.platform; (async () => { const export_list = await import(`./serve/${this.platform}`); ENC. Configuration == 'overall' &&(this.request = this.magicRequest(export_list['config'])); For (let __function__ in export_list) {// There should be two rules for this function? (by name, according to the type classification) if (typeof export_list [__function__] = = = 'function' | | __function__! == 'config') {// This is the interface function that needs to be registered with the rented and, [is the function type | | name not config] this [__function__] = export_list [__function__] bind ({request: This.request})} else {// Configuration == 'independent' &&(this.request = this.magicRequest(export_list[__function__])); } } console.log('========== this', this); delete this.then; return this })(); } // MagicRequest (config: config) Return request.bind({config})} export {ServeCore, return request.bind({config})} export {ServeCore, return request.bind({config})} export {ServeCore, return request.bind({config})} export {ServeCore, encType } export default new ServeCore

First we define a class named Servecore, where Platform is the platform identifier (Party A), which is used to distinguish different platforms. Request is the processed, encapsulated request root. This can actually change all the time, as we’ll see later in the article.

Load files as needed

In the constructor we need to target the corresponding files on-demand dynamic platform is introduced in the this calss and processing, but unfortunately the js class constructor purpose is after return to construct an instance of, don’t support asynchronous operations (because the returned object will be a promise, here at run time error), Fortunately, we know that a class in JS is just a syntactic sugar for a function, and that the underlying class is still a function implementation, so I wrote a structure in the constructor like this:

constructor(ENC:encType = defaultConfig) {
    (async () => {
        // ... 
        delete this.then;
        return this    
    })();
}

The aim is to immediately execute an asynchronous arrow function as the return value, which in effect returns an instance of the Promise that will only return the created instance of the object (this) when it is resolved. Thus, our external await gets the instance of the completed asynchronous construction. I am “awaiting import” to await the file corresponding to the different parties for processing. Here is an example of a demo

A. Ts (Party A)

// Should the configuration be placed first? Export const config = {// TODO: function _base_url: {release: 'https://xxx.com', dev: 'https://xxx.com', test: 'string ',}, _header: {sign: (param) => {// The actual calling environment here is in the request, so the function is better? / /... Export async function getTest(params) {const res = await request < ResponseParam bb0 ({url: '/getInfo/test', method: 'POST', data: params, }); return res; } / /...


If I have something to do, I will go to work on it first. I will come back to make up for it later. There are still a lot of things not written clearly

xxx.tsx

import Service from '.. /.. /config/serve' // ... Const res = await Service.getTest(param); Console. log(res) // The IDE will report an error here but it will work fine

Graphic understanding (get a mind map if you’re interested)

UML diagrams are as follows

SequenceDiagram interface file (a.js) ->>+ ServeCore: config (configuration) and interface method ServeCore->>+request(encapsulated request root): Config (config)-> -> + ServeCore (a.js) -> -> + ServeCore: Interface method ServeCore->>+ xx. TSX (general page call): network interface method Note Right of Request (encapsulated request root): fully processed interface

A link to the

References: https://www.blackglory.me/asy…