react-native-easy-app details and uses fetch

react-native-easy-app Is a pure JS library that provides basic services for React Native App rapid development (supports IOS & Android), especially at the beginning of a project from 0 to 1, which can reduce the workload of developers by at least 30%.

react-native-easy-app mainly does these things:
1. Encapsulating the AsyncStorage allows developers to implement a persistent data manager in just a few lines of code.
2. Encapsulate fetch so that developers only need to focus on the foreground and background interaction logic and protocols of the current App, define the parameter settings and parse logic.
3. Re-encapsulating RN's View, Text, Image, FlatList controls to support events or icon and text when appropriate can effectively reduce nested logic in the layout.
4. Automatically multi-screen adapting by setting a reference screen size and resetting the dimensions of XView, XText and XImage

It may be argued that different App s have different requirements for Http requests, and how can third-party libraries possibly be fully encapsulated and, if so, overencapsulated?

There are 1,000 Hamlets in a thousand people's hearts. Perhaps my ideas can give you different inspiration, but it is also unknown?

Network request (fetch)

Let's start with an example of fetch usage given by React native:

  • Asynchronous requests (core code)
    fetch('https://facebook.github.io/react-native/movies.json')
    .then((response) => response.json())
    .then((responseJson) => {
      return responseJson.movies;
    })
    .catch((error) => {
      console.error(error);
    });
  • Synchronization Request (Core Code)

    try {
    // Note that the await statement here must be in a function that has an async keyword declaration
    let response = await fetch('https://facebook.github.io/react-native/movies.json');
    let responseJson = await response.json();
    return responseJson.movies;
    } catch (error) {
    console.error(error);
    }

    RN platform fetch request is very concise, let's see if react-native-easy-app request XHttp can also send requests quickly and easily?

  • Asynchronous Request (Core Code) Example 1

    import { XHttp } from 'react-native-easy-app';
    
    XHttp().url('https://facebook.github.io/react-native/movies.json').execute('GET')
    .then(({success, json, message, status}) => {
      console.log(json.movies)
    })
    .catch(({message}) => {
        showToast(message);
    })
  • Synchronization Request (Core Code) Example 2

    import { XHttp } from 'react-native-easy-app';
    
    const response = await XHttp().url('https://facebook.github.io/react-native/movies.json').execute('GET');
    const {success, json, message, status} = response;
    console.log(json.movies)
  • Asynchronous Request 2 (Core Code) Example 3

    import { XHttp } from 'react-native-easy-app';
    
    XHttp().url('https://facebook.github.io/react-native/movies.json').get((success, json, message, status)=>{
       console.log(json.movies)
    });

    By executing the three sample codes above, it is found that the output is consistent (an array of movie lists):

Through comparison, it is found that the use of XHttp is very similar to fetch provided by React Native platform, and its execute('get') method returns a promise object, so it can also send synchronous or asynchronous requests like fetch.In addition, the request can be sent as [method]+callback.

XHttp returned multiple parameters compared to the native fetch request. Let's print the response in Example 2 to see what's in it?Output results, formatted as follows:

  1. Success => [true | false] Identity of the success or failure of the request (default is based on Http's request status code: [status >= 200 && status < 400].
  2. JSON => [Json Object | originText] defaults to the JSON object returned by the request, and you can specify to return a plain text string if the result of the request is a nonstandard Json, such as an XML structure or other, or to specify the data structure returned by the request through a custom configuration.
  3. By default, when a request succeeds: [code+url], when it fails: [error message+code+url], when the developer specifies a specific resolution, it is up to the developer.
  4. Status by default is the status code for Http requests, which can be formulated by developers to return custom business logic request status codes

From the example above, XHttp of react-native-easy-app can send Http requests as quickly and easily as fetch does. It also contains request codes, error messages, and results are converted into json objects, making it easier to send requests with us.

However, in actual App development, our Http request framework requires more than just sending simple Http requests, such as printing request logs, setting header parameters, unifying parsing logic, and possibly even processing json data whose returned structure is not standard.

Let's see what XHttp from react-native-easy-app meets our needs:
Note: Each of the above three examples has its own merits. Where the request examples are sent below, I choose to use Request Example 3 as an example.

  • Requirement 1: Can support get, post, put, delete and other basic common types of requests:
    • The framework automatically handles the body problem of the request based on the type of request entered.
    • 1. There is no problem sending requests via XHttp's execute('method').
    • 2. What do I do when I ask questions in the form of method + callback (90% of cases are satisfied)?There is no need to worry that the framework provides another way to do this:
      XHttp().url('https://facebook.github.io/react-native/movies.json').request('HEAD', (success, json, message, status) => {
      console.log(json.movies);
      })
  • Requirement 2: Ability to support commonly used contentType settings such as application/json, multipart/form-data, application/x-www-form-urlencoded, etc.
    • Of course, it's not just a simple pass-on parameter; it must be able to handle the body in the normal way based on the requested contentType, and if the contentType is multipart/form-data, it will use FormData to receive the parameters passed in by the splice developer.
    • 1. XHttp has three ways to set contentType, and three commonly used ways have been extracted as follows: direct setting; header setting; direct method specifying.Once the developers have set the appropriate way, they can safely send Http requests and the rest of the framework will handle them (for example, Upload Picture Settings):

  • Requirement 3: Supports timeout settings; Supports log printing; Supports splicing returning non-standard Json and baseUrl
    • The principle of request hyper is through Promise.race Realization;
    • 1. Since timeout requests are not entirely part of a particular request, a common configuration object is introduced: XHttpConfig, which allows developers to set request timeout configuration in two ways:
import { XHttpConfig } from 'react-native-easy-app';

XHttpConfig().initTimeout(300000); //Global configuration, set timeout of 30 seconds for all Http requests

XHttp().url('https://facebook.github.io/react-native/movies.json').timeout(15000)//Set the current request timeout to 15 seconds
    .get((success, json, message, status) => {
    })
  • 2. Log printing is also done by setting XHttpConfig().initHttpLogOn(true) to true. After setting, we send a request to see the console's output log:
    XHttpConfig().initHttpLogOn(true);
    XHttp().url('https://facebook.github.io/react-native/movies.json').get((success, json, message, status) => {
    })

You can see that the console prints out detailed logs, is it convenient?

  • 3. Currently 99% of mobile development scenarios use json format data for front-end and back-end interaction, but it is difficult to guarantee that App does not use Http requests in non-standard json data format in some special cases.For example, you need to request some old websites or use some old open interfaces from third parties.At this point, you only need to specify the return of pure file data. Next, find an interface that returns xml format and ask to see the result:
let url = 'http://www.webxml.com.cn/WebServices/MobileCodeWS.asmx/getDatabaseInfo'
XHttp().url(url).pureText().get((success, text, message, status) => {
    console.log('XML data', text)
})

The console output is as follows (data returned as plain text specified by pureText() of XHttp):

  • 4. As for the splicing of baseUrl, the purpose is to reduce the duplication of unnecessary baseUrl in App development (the program determines whether the incoming url is a fully spliced BaseUrl on demand) using the following methods:
import { XHttpConfig, XHttp } from 'react-native-easy-app';

XHttpConfig().initBaseUrl('http://www.webxml.com.cn/WebServices/');
XHttp().url('MobileCodeWS.asmx/getDatabaseInfo').get((success, text, message, status) => {
    console.log('XML data', text)
})
  • Requirement 4: The public params, headers can be set freely, and the header and param data of the current request can be set freely when sending Http requests.
import { XHttpConfig, XHttp } from 'react-native-easy-app';

XHttpConfig().initHttpLogOn(true)
    .initBaseUrl('https://facebook.github.io/')
    .initContentType('multipart/form-data')
    .initHeaderSetFunc((headers, request) => {
        headers.headers_customerId = 'headers_CustomerId001';
        headers.headers_refreshToken = 'headers_RefreshToken002';
    })
    .initParamSetFunc((params, request) => {
        params.params_version = 'params_version003';
        params.params_channel_code = 'params_channel_code004';
        params.testChannel = 'testChannel005';
    });

XHttp().url('react-native/movies.json')
    .header({'Content-Type': 'application/json', header_type: 'header_type006'})
    .param({paramUserName: 'paramUserName007', testChannel: 'testChannel008'})
    .post((success, text, message, status) => {
    })

As you can see from the code, with the XHttpConfig configuration, we set the public heders, params, and then when sending requests through XHttp, we set specific header and param values, modified the type of contentType, and changed to post requests. Execute the code to see the console log content:

From the log printed by the console, it is clear that all parameters (except 005) from 001 to 008 can be set to the request effectively.But why are common parametersParams.testChannel='testChannel005';The settings do not work because the private parameters of the interface request in XHttp also have a parameter: testChannel:'testChannel008', which has the same Key, so they are overwritten by the private parameters of the interface (careful students can also find that'Content-Type'in the log:'application/json', the type of contentType is also overridden, which indicates that the private parameters of the interface have a higher priority, which is reasonable and makes the request of the interface more flexible and convenient.

The data returned is in the following format:

{
  "ticker": {
    "base": "BTC",
    "target": "USD",
    "price": "5301.78924881",
    "volume": "179358.70555921",
    "change": "-21.18183054"
  },
  "timestamp": 1584291183,
  "success": true,
  "error": ""
}

You can see that there are three main fields in the data structure returned by the interface:

  1. The basis for the success interface logic success and failure.
  2. If the error interface fails, it contains error information.
  3. The principal of the primary data returned by the ticker interface.

Before XHttp sent the request, the success of the interface was still determined by the status of http, which indicated that the request could not be met.Cryptonator.comWeb site api data uniform parsing basic requirements, how to customize data parsing?Let's try it.

import { XHttpConfig, XHttp } from 'react-native-easy-app';

XHttpConfig().initHttpLogOn(true)
    .initBaseUrl('https://www.cryptonator.com/api/')
    .initParseDataFunc((result, request, callback) => {
        let {success, json, message, status} = result;
        callback(success && json.success, json.ticker || {}, json.error || message, status);
    });

XHttp().url('ticker/btc-usd').get((success, json, message, status) => {
    console.log('success = ' + success);
    console.log('json    = ' + JSON.stringify(json));
    console.log('message = ' + message);
    console.log('status  = ' + status);
});

Let's look again at the request log output by the console and the contents of the four standard parameters printed by the Http request:

No, json's corresponding value is the data structure returned: ticker's corresponding data.Other fields cannot be reflected because the data fits exactly the default criteria or is empty.How does this work?

Because of the initParseDataFunc method of XHttpConfig, we redefine the value of the standard field returned by the interface request:

  1. Success => success &&Json.successSuccess is considered only if the interface request and the returned success tag are both true
  2. JSON =>Json.tickerDirect readJson.tickerValue of (if empty, returns an object without any attributes)
  3. Message =>Json.error|| message takes precedence in getting error information returned by the interface (read error information from Http request if empty)
  4. Status => Status still uses the status of Http because some APIs do not have code judgement markers

This solves the problem of customizing the parameters returned by the Http request. At this time, someone might say: My app not only requests a background or third-party interface, but also different data structures returned by different backgrounds. What happens in this case?Don't worry, this is also a solution:

FHttp().url('https://api.domainsdb.info/v1/domains/search')
   .param({domain: 'zhangsan', zone: 'com'})
   .contentType('text/plain')
   .rawData()
   .get((success, json, message, status) => {
       if (success) {
           console.log('rawData', JSON.stringify(json))
       } else {
           console.log(message)
       }
   })

The logs requested to be printed by the interface are:

The request was still successful, and the parameters were fine, because a tag, rawData(), was added to send the Http request for special processing to mark that the current Http request needs to return the original data without any parsing (setting this tag automatically ignores user-defined data parsing).

  • Option 2 (It is also possible for an App to request transitions from several different platforms or older versions, and there are not a few interfaces of different styles), and in this case the style of parameters that may be requested and the public parameters have different requirements, which is more complicated. Can this be handled?The answer is yes:

Assuming that App is requesting three platforms: SA, SB, SC, which require different common parameters (including header s) and the data structure returned is inconsistent, we can do this so that both configuration and request can be implemented completely independently:

import { XHttpConfig, XHttp } from 'react-native-easy-app';

XHttpConfig('SA').initHttpLogOn(true) ...

XHttpConfig('SB').initHttpLogOn(true) ...

XHttpConfig('SC').initHttpLogOn(true) ...

const url = 'https://facebook.github.io/react-native/movies.json';

XHttp('SA').url(url) .get((success, json, message, status) =>{
});

XHttp('SB').url(url) .get((success, json, message, status) =>{
});

XHttp('SC').url(url) .get((success, json, message, status) =>{
});

It's that simple. Configurations and requests can be distinguished by serverTag. By default, the same configuration is used, but if you specify a new serverTag, you can specify which Http request to use when sending an Http request through serverTag, so that within the same app, there is no pressure to request different servers and to process data returned by different servers.

From the example above, we can see that three common configuration methods for XHttpConfig: initHeaderSetFunc, initParamSetFunc, initParseDataFunc are face-to-face programming modesThese methods also have a common parameter, request (the second parameter), which contains all the original information requested, so there is more room for imagination and you can explore it.

  • Some students may find it convenient to set the parameters of the framework, but do I want to completely implement the data analysis by myself?Of course, through the fetch method, the promise of the original fetch request is returned, and the framework does nothing:

  • Some students also thought that it was easy to parse the frame. I want to use the frame parsing completely, but some parameters are placed in the header. How can I get the header data of the response when parsing the data?Don't worry about this. In all the examples, the parsing callback for my list has four parameters: (success, json, message, status), but there are actually five parameters. Fifth is response, which is the reponse returned by fetch, from which you can get any data you want, including headers
const url = 'https://facebook.github.io/react-native/movies.json';

XHttp().url(url).get((success, json, message, status, response) => {
    console.log(JSON.stringify(response.headers))
});

const {success, json, message, status, response} = await XHttp().url(url).execute('GET');
console.log(JSON.stringify(response.headers))
  • It might also come to mind that there is an application scenario, oauth2, that needs special treatment:
    1. Send request req1 because access Token failed
    2. The program retrieved the new accessToken via refreshToken
    3. Re-request req1 with new accessToken

What about this application scenario?

XHttpConfig()
    .initHttpLogOn(true)
    .initBaseUrl(ApiCredit.baseUrl)
    .initContentType(XHttpConst.CONTENT_TYPE_URLENCODED)
    .initHeaderSetFunc((headers, request) => {
        if (request.internal) {
            Object.assign(headers, AuthToken.baseHeaders());//Add Base Parameter
            headers.customerId = RNStorage.customerId;
            if (RNStorage.refreshToken) {//If refreshToken is not empty, stitch
                headers['access-token'] = RNStorage.accessToken;
                headers['refresh-token'] = RNStorage.refreshToken;
            }
        }
    })
    .initParamSetFunc((params, request) => {
        if (request.internal && RNStorage.customerId) {
            params.CUSTOMER_ID = RNStorage.customerId;
        }
    }).initParseDataFunc((result, request, callback) => {
    let {success, json, response, message, status} = result;
    AuthToken.parseTokenRes(response);//Resolve token
    if (status === 503) {//Specified Token Expiration Mark
        this.refreshToken(request, callback)
    } else {
        let {successful, msg, code} = json;
        callback(success && successful === 1, selfOr(json.data, {}), selfOr(msg, message), code);
    }
});
static refreshToken(request, callback) {
    if (global.hasQueryToken) {
        global.tokenExpiredList.push({request, callback});
    } else {
        global.hasQueryToken = true;
        global.tokenExpiredList = [{request, callback}];
        const refreshUrl = `${RNStorage.baseUrl}api/refreshToken?refreshToken=${RNStorage.refreshToken}`;
        fetch(refreshUrl).then(resp => {
            resp.json().then(({successful, data: {accessToken}}) => {
                if (successful === 1) {// Get a new accessToken
                    RNStorage.accessToken = accessToken;
                    global.tokenExpiredList.map(({request, callback}) => {
                        request.resendRequest(request, callback);
                    });
                    global.tokenExpiredList = [];
                } else {
                    console.log('Token Expired, logged out');
                }
            });
        }).catch(err => {
            console.log('Token Expired, logged out');
        }).finally(() => {
            global.hasQueryToken = false;
        });
    }
};

I will not elaborate the direct code here, please read the source code or reference directly react-native-easy-app Library Corresponding Example Project, as far as the principle is concerned, at the time of the request, the method reference of the initial request is saved in the request and named resendRequest. If you get a new token, request the resendRequest method again and pass in the original parameters.

There may be students who think that react-native-easy-app encapsulates XHttp and XHttpConfig in too many ways and parameters to remember that although the framework is good, it is not easy to use. You may need to refer to the sample project to write this now (I will complete the instructions later).

Of course, did you find that when using these library methods, the code has hints?That's right.Because I added a dts description document for my main method, it's OK to write code without remembering that the method name parameter was written directly through the code autoprompt (autoprompt has a better experience on webStorm):

###react-native-easy-app (3) View, Text, Image, Flatlist

To learn more, please move to npm Or github view react-native-easy-app , active code and use Example Welcome to your friends Star!

If you have any questions, you are welcome to join RN technology QQ communication group

Tags: Mobile JSON React github xml

Posted on Sat, 30 May 2020 12:57:18 -0400 by Deany