This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

I have been developing RESTful API for less than half a year, and I feel that RESTful API is the most disgusting API. It makes front-end workload surge, makes front-end students write endless business logic, and makes front-end students enter 996.

The front end of the job market is increasingly demanding RESTful API project practitioners. Here I just want to tell the front end students encounter this kind of position, pay a few more K is not too much, why? This is quite the back-end part of the workload to the front end of the students, more than a few K pay too much.

Let’s start with what RESTful apis are.

What is a RESTful API

RESTful apis are resource-oriented interfaces that use urls to locate resources and HTTP verbs (GET, POST, DELETE, PUT, and PATCH) to describe operations.

A RESTful API can be thought of as a resource-based interface, whereas previously the back-end interface we requested was a consumer interface. Let’s use an example to explain the difference between a resource interface and a consumer interface.

For example, there is a list of logs, and each log has a list of comments and a list of likes. If you use a consumer interface for development, you only need a log list interface getLogList, which returns the data structure shown below. You can render the log list directly from the data returned by the interface.

[{id: "002 e5657ad104feb986c3b640647cc08", the text: 'I am a log' publishTime: 1635157425, publishName: 'zhang' publishId: '7738290823676234234' comments: [{id: '00 dfawrw4feb986c3b640647cc08, text:' I am a comment, createTime: 1635157425, commentName: '32894878275883957',}], supports: [{id: '00 dfawrfsgsfg86c3b640647cc08, createTime: 1635157425, supportName:' Cathy 'supportId: ' ',}]}]Copy the code

If the resource-based interface is used for development, the log list interface will be divided into four resource-based interfaces, which are respectively:

  • User Resource InterfacegetUseList, you can query the user information based on the user ID. The data format is as follows:
[{id:'78695979086612', name:' Zhang SAN '}]Copy the code
  • Log Resource InterfacegetLogList, you can query the log information based on the log ID and provide paging capability. The data format is as follows:
[{id: "002 e5657ad104feb986c3b640647cc08", the text: 'I am a log' publishTime: 1635157425, publishId: '7738290823676234234',}]Copy the code
  • Comment Resource InterfacegetCommentList, you can query the corresponding log information based on the comment ID and provide paging capability. The data format is as follows:
[{id: '00 dfawrw4feb986c3b640647cc08, text:' I am a comment, createTime: 1635157425, commentId: '32894878275883957',}]Copy the code
  • Like the resource interfacegetSupportList, you can query the corresponding log information based on the comment ID and provide paging capability. The data format is as follows:
[
  {
    id:'00dfawrfsgsfg86c3b640647cc08',
    createTime: 1635157425,
    supportId: '32894878275883957',
  }
]
Copy the code

The publishName field in the returned log data is missing because the publishName can be retrieved from the publishId user resource.

Comments and supports, which represent the comment list and the like list, are not supported.

CommentName and supportName in the comment and like data indicate that the commentName and the like name are missing and must be obtained from the commentId or supportId user resources.

From the above example, we can clearly feel the difference between resource interface and consumption interface. As a front-end, which interface would you prefer? The answer is definitely a consumable interface, where one request is done, eliminating the need to request multiple interfaces and concatenate data.

However, as a backend student, I will definitely prefer resource-based interfaces, which are relatively pure. For example, one day the product requires the development of a user comment and like record page, at this time the backend students do not need to develop a consumer interface to return comments and like data, directly ask the front-end students to use comment resource interface, like resource interface, user resource interface to develop this interface. Quite a bit of the work of the back end is transferred to the front end for development.

Nowadays, more and more companies adopt this mode of development. The front-end gradually takes over the development of business logic, and the back-end focuses on data acquisition and data reliability.

In order to keep their jobs, the front end should learn how to develop RESTful apis. Here are four skills I think are necessary to develop RESTful apis.

Learn to async/await

The interface is returned asynchronously and is handled with promises. This is typically the case when developing with resource-based interfaces

import * as Api from '@/api/log' const getLogs = () => { APi.getUseList() .then(res => { Api.getLogList() .then(res1 => { Api.getCommentList() .then(res2 => { //... }) .catch(err2 => { //... }) Api.getSupportList() .then(res3 => { //... }) .catch(err3 => { //... }) }) .catch(res => { //... }) }) .catch(err => { //... })}Copy the code

The above code has a serious hell callback that needs to be fixed with async/await.

import * as Api from '@/api/log'
const getLogs = async () => {
  const useList = await APi.getUseList();
  const logList = await APi.getLogList();
  const commentList = await APi.getCommentList();
  const supportList = await APi.getSupportList();
}
Copy the code

Async /await is an asynchronous operation performed synchronously with a try… Catch to handle an error.

import * as Api from '@/api/log' const getLogs = async () => { try { const useList = await APi.getUseList(); } catch (err) { console.log(err); }}Copy the code

To avoid having trys everywhere in your code… Catch, when wrapping axios, creates an object with state, such as api.getuselist () returns such an object.

let result = {
  success:false,
  data:{},
}
Copy the code

Where, SUCCESS indicates whether the request is successful, true indicates that the request is successful, false indicates that the request is failed, and data indicates that the requested data is returned.

When an error message is returned, set result.success to false and assign the error message to result.data. Resolve (result); resolve(result); resolve(result); Get rid of catch.

import * as Api from '@/api/log' const getLogs = async () => { const res = await APi.getUseList(); If (res.success) {// request successful processing} else {// request failed processing}}Copy the code

Learn to make concurrent requests

Processing asynchronous requests as synchronous requests with await blocks. This is where concurrent processing comes in.

Before using concurrency, understand that the interfaces that are put together for concurrent requests satisfy those business scenarios that use different Promise static methods, such as:

  • Wait for all concurrent requests to succeed before proceeding to the next step or terminate the operation if only one interface fails, using promise.all ().

  • Any () is used to proceed to the next step as long as one of the concurrent request interfaces succeeds.

  • Wait for the interfaces of the concurrent requests to complete, with or without success, before proceeding to the next step, with promise.allSettled ().

There are also two cases of concurrent requests:

  • Fixed parameters for concurrent requests

    The promise.all (), promise.any (), promise.allSettled () parameters are fixed.

    Promise.all([APi.getCommentList(),APi.getSupportList()]);
    Copy the code
  • Dynamic parameter concurrent request

Promise.all(), promise.any (), promise.allSettled () parameters are dynamic.

For example, to get all the comment data belonging to a log list, you could iterate through the log list, request the comment resource interface with each log ID, process the concurrent request, construct an array of asynchronous requests using the Map method, and pass the set as a parameter to promise.all.

import * as Api from '@/api/log' const getCommentByLogId = async (logId) => { const comment = await APi.getCommentList(logId); if (comment.success) return comment.data.data; return []; } const getAllComment = async () => { const logs = await APi.getLogList(); if (! logs.success) return; logs = logs.data.data; const jobs = logs.map(item => { if (item) { return getCommentByLogId(item); } }) const result = await Promise.all(jobs); return result.flat(); }Copy the code

You might be asked if you have an error handling of the promise.all () result. If one of the getCommentByLogId(item) fails and returns an error message, then there is only one error message in the result array.

In async, an async function returns a return on success and a throw returns a return on failure. In the getCommentByLogId asynchronous function, only a return is used to return the result, which means that the getCommentByLogId execution will only be successful.

const test = async (num) =>{
  if(num > 2){
    return num;
  }else{
    throw num
  }
}
Copy the code

When test(1) is executed, the return value can only be caught using catch, and when test(2) is executed, the return value can only be caught using THEN.

So how do you add a comment to the comment area of the corresponding log in the log list? Request the comment resource interface with the log ID in the traversal log list, and assign the value directly after the request succeeds.

import * as Api from '@/api/log' const getCommentByLogId = async (logId) => { const comment = await APi.getCommentList(logId); if (comment.success) return comment.data.data; return []; } const getLogs = async () => { let logs = await Api.getLogList(); if (! logs.success) return; logs = logs.data.data; const jobs = logs.map(async (item) => { item.comments = await getCommentByLogId(item.id); return item; }) await Promise.all(jobs); return logs };Copy the code

Learn to recursive

Now there is a requirement to get all the comment data, and the comment resource interface is paginated. In this case, recursion is used, as shown below:

const getComment = async (page = 1, result = []) => { const data = { page, prePage: 100, } let comment = await Api.commentList(data); if (! comment.success) return []; comment = comment.data.data; if (comment.length > 0) { result = [...result, ...comment]; page = page + 1; return this.getComment(page, result); } else { return result } } const init = async () =>{ const comments = await getComment(); console.log(comments); // All comment data}Copy the code

Learn how to construct tree structured data

In RESTful apis, servers usually only return array data. If they need tree data, they have to construct their own data.

For example, the department resource interface returns an array of departments with the following structure:

Const depList = [{"id": "1394491627984502786", "id": "name",}, {"id": "1394491628185829378", "name": "ParentId ": "1394491627984502786",}, {" ID ": "1394491628659785729", "name": "parentId": }, {"id": "1394491629515423745", "name": "parentId": "1394491628005474306",}, {" ID ": "1394491629888716802", "name": "C group operation ", "parentId": "1394491628185829378",}, {"id": "C group operation ", "parentId": "1394491628185829378",}, {"id": "1394491630131986433", "parentId": "1394491628185829378",}, {" ID ": "1395669342024445954", "name": "ParentId ": "1395669342024445954",}, {"id": "parentId": "1395669342024445954",}, {"id": "parentId": "1395669342024445954",} ", "name": "Marketing Department ",},]Copy the code

CreateTree (createTree, createTree); createTree (createTree, createTree);

const createTree = (data) => { let tree = []; let dataMap = {}; For (const node of data) {// Map dataMap[node.id] = node; node.children = []; // parentId if the parentId is empty, it indicates the first-layer node in the tree structure if (! node.parentId) { tree.push(node); For (const node of data) {// parentId if the parentId is empty, it is the first node in the tree structure, skip loop if (! node.parentId) continue; const child = dataMap[node.id]; const parent = dataMap[node.parentId]; // No child data or parent data found in dataMap, skip loop if (! child || ! parent) continue; Parent.children.push (child); parent.children.push(child); parent.children.push(child); } return tree; };Copy the code

Comment on the prize

“Welcome to the discussion in the comments section. The nuggets will be giving away 100 nuggets in the comments section after the diggnation project. See the event article for details.”