What is a front-end API module?

First of all, what do we mean by front-end API modules?

In the front-end code (this does not include BFF, BFF is divided into “back-end”) are requested the back-end service interface code, under normal circumstances, a backend interface may be used by multiple pages, so we usually put the backend interface API related front-end code in one module of unified management, to initiate the request code, reference the module, Then use the method of specifying API to initiate the request, so as to achieve the purpose of reuse code, unified management, and this management API module, I named it as “front-end API module”.

I’m not quite sure what we call it in the front circle, so I’ll just call it that. If you can, let me know in the comments section what better to call this 😂!

History project

First of all, let’s talk about the current project plan and existing problems.

Solution: Each service manages a separate API module

We call a large category of functional modules services, such as product services, user services, etc., and then use the service category to divide the code into different directories or microservices on both the front and back ends.

Back-end interfaces are provided through microservices, such as/API /products/v1/ XXX for product services and/API /users/v1/yyy for user services.

The front end similarly provides separate APIS modules under each service directory. For example, in the Products directory, there is an apis. Js file exporting apis module that defines API address constants for all back-end Products services. When a request is made in the page code, it is made by importing the module, then using the constant name exported by the module, and then using the request method.

// ./products/apis.js

const VERSION = 'v1';
const SERVICE = 'products';

const PRODUCT_LIST = `/api/${SERVICE}/${VERSION}/list`;

export default {
  PRODUCT_LIST,
};
Copy the code
// ./products/pages/list.js

import APIS from '.. /apis';
import axios from 'axios';

const { PRODUCT_LIST } = APIS;

axios.get(PRODUCT_LIST, {
  params: {
    pageIndex: 1.pageSize: 10,
  }
}).then(() = > {
  // ...
}).catch(() = > {
  // ...
});

Copy the code

With this scheme, when the API interface address changes, you just need to change the constant value in apis.

The problem

1. When multiple services use the same API, the API of multiple services needs to be modified, which is prone to leakage.

2. When the use of business code is not standardized, THE API module is not introduced in accordance with the specification, and when the API address is modified, the change situation occurs;

3. The business code also needs to introduce its own request library, which can also be implemented in the API module;

Improved solution

Therefore, it is necessary to improve the program to solve the problems existing in the historical program.

1. Extract to public service API module or independent API service

Put all apis away and manage them in a common service or a separate service instead of being scattered across each service. The advantage of this approach is that no product service uses the same API service, facilitating standardized management. Changes to API, request interception, or other enhancements need only be made in one API service, rather than in each product service. In this way, there will be no need to change the modification of multiple errors, missed changes.

Of course, no plan is perfect, and the choice of plan is always the art of balancing.

The problem with such a scheme also has some unsatisfying problems.

First, it leads to common resource loading costs and memory costs, and there is some redundancy. When loading public resources, the API module code must be loaded first. Objects exported by the API module occupy memory space for a long time. To solve the problem, we can reduce the resource loading cost by loading on demand, and reduce the memory cost by caching data (sessionStorage, etc.) and reading it when needed.

Secondly, the development process increases the cost of code management. When the public service code and the product service code are separated from each other, it is important to be aware of the code versions of the different code bases (often referred to as code branches), otherwise the product service may refer to a historical version of the public module, resulting in the absence of the corresponding API, or the API does not work.

On the whole, the new scheme does more good than harm.

2. API module provides more complete functions

In the previous scheme, only THE API address was provided, which was very limited. Therefore, in the new scheme, we not only provide the API address, but also need to treat each API as a complete request function, provide default request parameter values, and enhance the fault tolerance of the request.

// ./apis/products.js

import axios from 'axios'; 

const VERSION = 'v1';
const SERVICE = 'products';

const PRODUCT_V1 = `/api/${SERVICE}/${VERSION}`;

// Get the product list interface
export function getProductList(params = {}) {
  return axios.get(`${PRODUCT_V1}/list`, {
    params: {
      // Default parameters
      pageIndex: 1.pageSize: 10.// The argument passed in. params, } }); }// Add product interface
export function addProduct(data) {
  if(! data || ! data.name) {return Promise.reject('The [name] is required! ');
  }
  return axios.post(`${PRODUCT_V1}`, {
      data: {
          ...data,
          name: data.name.trim(),
      }
  });
} 

// Modify the product interface
export function addProduct(params, data) {
  if(! params || ! params.id) {return Promise.reject('The [id] in params is required! ');
  }
  if(data && data.name) {
       return Promise.reject('The data.name is not allowed to be modified! ');
  }
  return axios.put(`${PRODUCT_V1}/${params.id}`, {
      data,
  });
}  

Copy the code
// ./apis/index.js
import axios from 'axios'; 
export * as products from './products';

// Intercept the request
axios.interceptors.request.use(function (config) {
  // Do something before request is sent
  return config;
}, function (error) {
  // Do something with request error
  return Promise.reject(error);
});

// Intercept the response
axios.interceptors.response.use(function (response) {
  // Any status code that lie within the range of 2xx cause this function to trigger
  // Do something with response data
  return response;
}, function (error) {
  // Any status codes that falls outside the range of 2xx cause this function to trigger
  // Do something with response error
  return Promise.reject(error);
});
Copy the code
// ./products/pages/list.js
import { products } from './apis';

const { getProductList } = products;

getProductList()
  .then(() = > {
  	// ...
    })
    .catch(() = > {
  	// ...
    })
Copy the code