The React project I’m currently working on is gradually showing chaos in API usage, so I started the governance process. Here’s a record of the causes and consequences.

Before Governance
Background: The number of API requests in the project has reached 100+.
Take an example of two API files, user-api.ts and setting-api.ts:
...
export const getUserList = (params: IUserQuery) => axios.get('/user/api/v1/users', { params });
...
...
export const getCountrySetting = (params:ICountrySettingParam) => axios.get('/setting/api/v1/country', { params });
...
Current APIs are all directly exported specific functions. This design has the following problems:
- Naming limitations: Because there’s no concept of namespaces, function names need to accurately express what the request does. Of course, they should also indicate that it’s an API request. As shown above, it’s hard to tell that it’s an API request when using it. Additionally, team members’ skills vary, and without constraints, API naming becomes chaotic.
- Redundant base paths: In a single API file, many requests have the same prefix, causing repetition.
- Tight coupling: API files are directly imported wherever they’re used. If any changes occur, the outer layers need to be modified accordingly.
After Governance
To improve the maintainability of the API layer, the following solution was finally adopted.
First, let’s show the code
export class BaseApi {
basePath: string;
constructor(basePath: string) {
this.basePath = basePath;
}
}
...
class UserApi extends BaseApi {
export const getAll = (params: IUserQuery) => axios.get(`${this.basePath}/v1/users`, { params });
}
const userApi = new UserApi('/user/api');
export { userApi };
export * from './user-api';
Benefits After Improvement
- Using object-oriented approach makes each API module cohesive and easy to manage, e.g., shared basePath can be extracted.
- With class objects (namespaces), using
userApi.getUserListclearly indicates it’s an API request when reading code. - The index file directly exports API instances for easy use, avoiding importing multiple API files, and internal API changes are somewhat opaque to external layers.
- As a class, theoretically we can instantiate different objects with different property values, which improves flexibility.
API Method Naming Guidelines
The above only addresses API management. To improve the readability of individual APIs, the team discussed and formed a set of naming guidelines
Need continuous improvement.
Recommendations
- getOne*
- getAll*
- update*
- create*
- delete*
- export*
- download*
- is optional and depends on whether a noun is needed to more clearly reflect the method’s purpose.
API Layer Design in Angular
Because I did Angular development for 1-2 years before, I’ll extend this to discuss how it’s done in Angular.
In Angular, we create ApiService classes where each request is a function. When used in specific components, we get an instance of this ApiService and then operate on a specific request. This scheme seems familiar?
Yes, the governance scheme above is basically consistent with the official Angular scheme. So, behind technology are principles and design, which are framework-agnostic.
Final Thoughts
After quickly adjusting the API layer, the overall look is more comfortable now — happy. But the path of governance and refactoring never stops; let’s continue to improve.

