The Koa middleware implements the API Undo function, and the koa middleware apiundo

Source: Internet
Author: User

The Koa middleware implements the API Undo function, and the koa middleware apiundo
The Koa middleware implements the API's Undo function. The API's Undo function

Students who have used Gmail or 163 mail often see that when performing some operations on the mail, a message similar to Toast appears (the general meaning is: The operation has been completed, and whether to cancel it), as shown in:

When you click undo, the previously executed operations can be restored. This design is a great remedy for user misoperations.

I have heard of an interactive design statement before. Do not bring up Alert to allow users to choose "OK" or "cancel" during each step. A better way is to execute the operation, then let the user Undo.

Solution for implementing API Undo

In fact, Undo is a very old technology that is everywhere in the editor, but it is rarely used in API design. I have been using Node for Development recently, so I want to use Node to implement the Undo API.

First, we need to clarify the following points:

  • Not all APIs require Undo. For example, an interface for obtaining data is completely unnecessary (and logically cannot be implemented)
  • Only the last operation can be performed on the user.
  • Undo is in the user dimension, and users cannot perform operations by other users.
Traditional solution (Plan ):
  • The Undo logic needs to be provided for all interfaces that require Undo;
  • This method needs to be called when the user wants to perform the last Undo operation (usually involving database operations ).
New Plan B ):
  • Provides the Undo service in Middleware (similar to the interceptor in Java) mode.
  • Put the API logic that requires Undo into the specified queue for delayed execution
  • When the Undo interface is called, the last operation is removed from the delayed queue.
  • Call other interfaces to execute the logic in the delayed queue immediately
Advantages of solution comparison: solution:
  • You can perform undo operations on any interface;
  • The logic is simple. database operations are not required for undo operations;
Solution B:
  • Operations actually reflect the database;
  • No need to limit the undo expiration time;
Disadvantage solution:
  • After accessing the undo interface, you can access the non-undo interface. Previously, the logic cannot be undo;
Solution B:
  • The logic is complicated, and undo requires database operations;
  • Not all operations can be undo;
Solution implementation

By comparing the above scheme, I found that Plan A is simpler and more flexible, so I decided to implement Plan.

Koa's middleware is very powerful (similar to the interceptor in Java web Development). It can intercept all requests and execute some logic, for example, to calculate the response time of API requests, we can use this feature to delay the execution of Undo APIs.

First, we need to set the Undo timeout, and those APIs need Undo:

var apis = (options || {}).apis;var expired = (options || {}).expired || 3000;

You must also specify the users currently accessing the API:

/** * `x-identify-key` is used to identify the user of this request, * one user can not undo another`s request. */var user = context.header['x-identify-key'];

Then the API logic is delayed:

var undo = yield delayNext(user, expired, context);

If the Undo interface is not called, the execution logic is executed; otherwise, 'undo 'is returned ':

if (!undo) { return yield next; }this.body = 'undo';

If you call the Undo interface to remove the logic of delayed execution, call other interfaces to execute the delayed logic immediately:

clearTimeout(undoObj.timeoutId);if (path === '/undo' && method === 'POST') {  undoObj.delayFn.call(undoObj.context, true);  context.body = 'done';  return;} else if (undoObj.delayFn) {  undoObj.delayFn.call(undoObj.context, false);}

The specific implementation logic is like this. The complete code is as follows:

/** * Store users' undo context *  * @type {Object} */var undos = {};/** * Expose `undo` * * @param {Object} options Config object for undo * @example * { *   expired: 3000 * } */module.exports = function (options) {  var apis = (options || {}).apis;  var expired = (options || {}).expired || 3000;  return function* (next) {    var context = this;    var path = context.path;    var needUndo = false;    if (apis && Array.isArray(apis) && apis.length) {      needUndo = apis.filter(function (api) {        return path === api;      }).length;    }    if (!needUndo && path !== '/undo') { return yield next; }    var method = context.method;    /**     * Can not undo get request.     */    if (method === 'GET') { return yield next; }    /**     * 'x-identify-key' is used to identify the user of this request,     * one user can not undo another's request.     */    var user = context.header['x-identify-key'];    if (!user) { return yield next; }    var undoObj = undos[user];    if (undoObj) {      clearTimeout(undoObj.timeoutId);      if (path === '/undo' && method === 'POST') {        undoObj.delayFn.call(undoObj.context, true);        context.body = 'done';        return;      } else if (undoObj.delayFn) {        undoObj.delayFn.call(undoObj.context, false);      }    }    var undo = yield delayNext(user, expired, context);    if (!undo) { return yield next; }    this.body = 'undo';  };};/** * Block the logic for specified ms. * * @param {String} user The user's identity * @param {String} expired The expired ms * @param {Object} context The koa context object * @api private */function delayNext(user, expired, context) {  return function (callback) {    var delayFn = function (undo) {      delete undos[user];      callback(null, undo);    };    var timeoutId = setTimeout(delayFn, expired);    undos[user] = {      timeoutId: timeoutId,      delayFn: delayFn,      context: context    };  };}
Project-related

Currently, this project is hosted on Github.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.