preface

In react projects, we usually use the AXIos library, which is a Promise based HTTP library that runs in both the browser and Node.js. It has great features such as request and response interception, request cancellation, JSON conversion, client-side XSRF defense, and more. If you’re not familiar with Axios, you can refer to the Axios documentation.

The installation

// Use NPM to install axios; Install yarn add AXIos using YARNCopy the code

The introduction of

In the project root, create a request folder and create an index.js and an api.js file. The index.js file is used to wrap our AXIos, and the api.js file is used to unify our interfaces.

// Add axios to index.js
import axios from 'axios';
// Introduce the QS module to serialize post data
import QS from 'qs';
// AntD's message prompt component, which you can change according to your OWN UI component.
import { message } from 'antd'
Copy the code

Environment switch

Our project environment may have a development environment, a test environment, and a production environment. We use node’s environment variables to match our default interface URL prefix. We need node’s global variables process, process.env.node_env to distinguish between development and production environments.

// Save environment variables
const isPrd = process.env.NODE_ENV == 'production';

// Distinguish between development environment and production environment base URL
export const basciUrl = isPrd ? 'https://www.production.com' : 'http://www.development.com'
Copy the code

The basic URL is exported here in case there are other places to use different resources, need to distinguish between production environment or development environment, import can be directly used.

Request to intercept

We can intercept a request before we send it, why intercept, what do we intercept a request for? For example, some requests require the user to log in before they can be accessed, or for POST requests, we need to serialize our submitted data. At this point, we can do what we want by intercepting the request before it is sent.

// Set the axios base path
const service = axios.create({
  baseURL: basicUrl
})
// Request interceptor
service.interceptors.request.use(config= > { 
  // Whether the token exists in the local store before each request is sent. Redux can also be used to obtain the token locally
  // If yes, add a token to the header of the HTTP request, so that the background can determine your login status according to the token
  // Even if the token exists locally, it is possible that the token is expired, so the return status is determined in the response interceptor
  const token = window.localStorage.getItem('userToken') | |window.sessionStorage.getItem('userToken');
  // Add a token to each request
  config.data = Object.assign({}, config.data, {
    token: token,
  })
  // Set the request header
  config.headers = {
    'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
  }
  config.data = QS.stringify(config.data)
  return config
}, error= > { 
    return error;
})
Copy the code

After login, the user’s token is stored locally through localStorage or sessionStorage. Then when the user enters the page (i.e. in main.js), the user will first read the token from the localStorage. If the token exists, the user has logged in. Then update the token status in Redux. Then, each time you request an interface, you will carry a token in the header of the request, and the background staff can judge whether your login is expired according to the token you carry. If you do not carry the token, it indicates that you have not logged in.

The response to intercept

// Response interceptor
service.interceptors.response.use(response= > {
  // Do different things according to the status code returned
  // The error status code must be agreed with the backend developer
  if (response.code) {
    switch (response.code) {
      case 200:
        return response.data;
      case 401:
        // Failed to log in
        break;
      case 403:
        // Token expiration method
        break;
      default:
        message.error(response.data.msg)
    }
  } else { 
    returnresponse; }})// Finally export the packaged AXIos
export default service
Copy the code

A response interceptor is the data that the server sends back to us and we can do something with it before we get it. For example, the above idea: if the status code returned by the background is 200, the data will be returned normally; otherwise, we need to make some errors according to the type of the error status code. The specific returned status code needs to be processed by the process and need to negotiate with the background developer. The message.error() method above is the library prompt component of ANTD that I introduced. Depending on your UI library, use the prompt component accordingly

Unified API management

A neat API is like a circuit board, no matter how complex it is, it can clear the entire circuit. As mentioned above, we will create a new api.js file and store all of our API interfaces in this file.

First we introduce our wrapped Axios in api.js

// Import our wrapped AXIos
import service from './index'
Copy the code

Now, for example, we have an interface like this, which is a POST request:

http://www.development.com/api/v1/articleEdit
Copy the code

We can wrap it in api.js like this:

export const apiArticleEdit = info= > service.post('/api/v1/articleEdit', info);
Copy the code

We define an apiArticleEdit method that takes one parameter, info, which is the parameter object we carry when we request the interface. Our wrapped AXIos method is then called, with the first argument being our interface address and the second argument being the info argument of the apiArticleEdit, which is the parameter object that the interface was requested with. Finally, export the apiArticleEdit through export.

We can then call our API from our page like this:

import React, { Component } from 'react'
 import { apiArticleEdit } from './request/api'
export default class App extends Component {
  componentDidMount() { 
    // Calls the API and provides two arguments
    let params = { type: 2.author: 'North Solitary Green Tea' }
    apiArticleEdit(params).then(res= > { 
      // Perform other operations after obtaining data successfully
      / /...
      console.log(res)
    })
  }
  render() {
    return (
      <div>
        
      </div>)}}Copy the code

For other API interfaces, you can extend them further in api.js. Tips, write a good comment for each interface!!

One of the benefits of API interface management is that we centralized the API. If we need to change the interface later, we can directly find the corresponding change in api.js, instead of going to every page to find our interface and then modify it. The point is, in case the amount of modification is relatively large. In addition, if we directly modify the interface of our business code, it is easy to move our business code and cause unnecessary trouble.

Okay, finally, the finished AXIos wrapper code.

// Add axios to index.js
import axios from 'axios';
// Introduce the QS module to serialize post data
import QS from 'qs';
// AntD's message prompt component, which you can change according to your OWN UI component.
import { message } from 'antd'

// Save environment variables
const isPrd = process.env.NODE_ENV == 'production';

// Distinguish between development environment and production environment base URL
export const basciUrl = isPrd ? 'https://www.production.com' : 'http://www.development.com'

// Set the axios base path
const service = axios.create({
  baseURL: basicUrl
})

// Request interceptor
service.interceptors.request.use(config= > { 
  // Whether the token exists in the local store before each request is sent. Redux can also be used to obtain the token locally
  // If yes, add a token to the header of the HTTP request, so that the background can determine your login status according to the token
  // Even if the token exists locally, it is possible that the token is expired, so the return status is determined in the response interceptor
  const token = window.localStorage.getItem('userToken') | |window.sessionStorage.getItem('userToken');
  // Add a token to each request
  config.data = Object.assign({}, config.data, {
    token: token,
  })
  // Set the request header
  config.headers = {
    'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
  }
  // Serialize the request parameters, otherwise the background will not receive the POST request parameters properly
  config.data = QS.stringify(config.data)
  return config
}, error= > { 
    return error;
})

// Response interceptor
service.interceptors.response.use(response= > {
  // Do different things according to the status code returned
  // The error status code must be agreed with the backend developer
  if (response.code) {
    switch (response.code) {
      case 200:
        return response.data;
      case 401:
        // Failed to log in
        break;
      case 403:
        // Token expiration method
        break;
      default:
        message.error(response.data.msg)
    }
  } else { 
    returnresponse; }})// Finally export the packaged AXIos
export default service
Copy the code