[Design Pattern] Encapsulate a network request lib - 4. API Template

Zhentiw發表於2024-12-01

When company's API become huge and always changing, if request-busis maintained by developers manually, it's not only time consuming but also error prone.

We can introduce some standard automation process to resolve the problem.

[Design Pattern] Encapsulate a network request lib - 4. API Template

Examples:

[Design Pattern] Encapsulate a network request lib - 4. API Template

[Design Pattern] Encapsulate a network request lib - 4. API Template

{
  "endpoints": {
    "article": {
      "publishArticle": {
        "path": "/api/article",
        "description": "Publish an article",
        "method": "POST",
        "auth": true,
        "idempotent": true,
        "cache": false,
        "pager": false
        // Other fields
      },
      "getArticles": {
        "path": "/api/article",
        "description": "Retrieve articles",
        "method": "GET",
        "auth": false,
        "idempotent": false,
        "cache": false,
        "pager": true
        // Other fields
      }
    }
  }
}

The generated code could be something like:

// /request-bus/template/article.ts

import { createIdempotentRequest } from 'request-core';

/**
 * Publish an article
 */
export const publishArticle = (() => {
	const req = createIdempotentRequest();
	return async (article: Article) => {
		return req.post('/api/article', article).then((resp) => resp.json());
	};
})();

/**
 * Retrieve articles
 */
export const getArticles = (() => {
	return async (page: number, size: number) => {
		const params = { page, size };
		return req.get('/api/article', { params }).then((resp) => resp.json());
	};
})();


/**
 * Retrieve articles
 */
export const getArticles = (() => {
  return async (page: number, size: number) => {
    return req.get('/api/article', {
      params: {
        page,
        size,
      },
    }).then((resp) => resp.json());
  };
})();

Override

It is possilbe that for the generated code, you might want to apply some changes. The way to do it is pretty simple:

export * from "./template"

export {publishArticle} from './patch'

We want have a patchfolder which contains the override, and using Javascript override directly to achieve the effect.

Summary

At the implementation level, I first consider the overall architecture of the request library.

I divide the request library into three layers, from bottom to top:

  1. Request Base Library: Responsible for the basic functionality of sending requests.
  2. Request Core Library: Responsible for implementing various upper-layer logics, such as concurrency, etc.
  3. Request Business Library: Responsible for encapsulating company-internal conventions at the code level.

From a structural perspective, considering that the specific implementation of the request base library may change (e.g., switching xhr to axios or fetch), to reduce the changes impacting upper-layer code, I apply the DIP (Dependency Inversion Principle). Inspired by front-end IOC (Inversion of Control) and DI (Dependency Injection) principles, the core library does not rely on a specific request base library. Instead, the request base library only needs to provide a TypeScript interface. The request core library can provide multiple implementation methods for the interface, and specific implementations can be injected into the business library. This completely decouples the core library from the specific implementation of the request library, allowing for flexible adjustments later.

Additionally, the business library is deeply tied to the company’s internal API documentation. In our project, there are an extremely large number of APIs. To reduce development and maintenance costs, I implemented an automated tool in Node.js. This tool parses standardized API documentation and automatically generates request template code for each endpoint. It also considers that some template code might not meet actual requirements, so a method is defined to supplement the template code. This approach reduces development workload while ensuring flexibility.


相關文章