execute(request, callback) {
    if (!request.input.controller || !request.input.controller.length) {
      callback(
        kerror.get("api", "assert", "missing_argument", "controller"),
        request,
      );
      return 1;
    }

    if (!request.input.action || !request.input.action.length) {
      callback(
        kerror.get("api", "assert", "missing_argument", "action"),
        request,
      );
      return 1;
    }

    // If there is a body, retrieve the targets if any
    const targets = request.getArray("targets", []);
    /**
     * Only index and collection as a pair or the targets parameter is allowed at the same time
     * otherwise we throw an error because we don't know which one to use to verify the rights
     */
    if (
      targets.length > 0 &&
      (request.input.args.index || request.input.args.collection)
    ) {
      callback(
        kerror.get(
          "api",
          "assert",
          "mutually_exclusive",
          "index, collection",
          "targets",
        ),
        request,
      );
      return 1;
    }

    if (
      request.input.headers &&
      has(request.input.headers, "origin") &&
      !this._isOriginAuthorized(request.input.headers.origin)
    ) {
      debug(
        "Reject request, unauthorized origin %s",
        request.input.headers.origin,
      );
      return this._executeError(
        kerror.get(
          "api",
          "process",
          "unauthorized_origin",
          request.input.headers.origin,
        ),
        request,
        true,
        callback,
      );
    }

    try {
      const executing = this.throttle(
        (req) => {
          // if the connection is closed there is no need to execute the request
          // => discarding it
          if (!global.kuzzle.router.isConnectionAlive(req.context)) {
            debug("Client connection dead: dropping request: %a", req.input);
            callback(processError.get("connection_dropped"), req);
            return;
          }

          debug(
            "Starting request %s:%s [%s]: %j",
            req.input.controller,
            req.input.action,
            req.id,
            req.input,
          );

          global.kuzzle.asyncStore.run(() => {
            global.kuzzle.asyncStore.set("REQUEST", req);
            global.kuzzle
              .pipe("request:beforeExecution", req)
              .then((modifiedRequest) => {
                let _request;

                return this.checkRights(modifiedRequest)
                  .then((newModifiedRequest) => {
                    _request = newModifiedRequest;
                    return this.rateLimiter.isAllowed(_request);
                  })
                  .then((allowed) => {
                    if (!allowed) {
                      if (
                        request.input.controller === "auth" &&
                        request.input.action === "login"
                      ) {
                        throw processError.get("too_many_logins_requests");
                      }
                      throw processError.get("too_many_requests");
                    }

                    return this.processRequest(_request);
                  })
                  .then((processResult) => {
                    debug(
                      "Request %s successfully executed. Result: %a",
                      modifiedRequest.id,
                      processResult,
                    );

                    return global.kuzzle
                      .pipe("request:afterExecution", {
                        request: _request,
                        result: processResult,
                        success: true,
                      })
                      .then((pipeEvent) => {
                        callback(null, pipeEvent.result);

                        // disables a bluebird warning in dev. mode triggered when
                        // a promise is created and not returned
                        return null;
                      });
                  })
                  .catch((err) => {
                    debug(
                      "Error processing request %s: %a",
                      modifiedRequest.id,
                      err,
                    );
                    return global.kuzzle
                      .pipe("request:afterExecution", {
                        error: err,
                        request: modifiedRequest,
                        success: false,
                      })
                      .then((pipeEvent) =>
                        this._executeError(
                          pipeEvent.error,
                          pipeEvent.request,
                          true,
                          callback,
                        ),
                      );
                  });
              })
              .catch((err) => {
                debug("Error processing request %s: %a", req.id, err);
                return global.kuzzle
                  .pipe("request:afterExecution", {
                    error: err,
                    request: req,
                    success: false,
                  })
                  .then((pipeEvent) =>
                    this._executeError(
                      pipeEvent.error,
                      pipeEvent.request,
                      true,
                      callback,
                    ),
                  );
              });
          });
        },
        this,
        request,
      );

      return executing ? 0 : -1;
    } catch (error) {
      request.setError(error);
      callback(error, request);
      return 1;
    }
  }
Execute the API request by
1/ check domain from origin header
2/ asking for a request slot,
3/ verify that the user is still connected
4/ checking if the requesting user has the right credentials
5/ send the request itself to the corresponding controller+action

@param {Request} request
@param {Function} callback
@returns {Number} -1: request delayed, 0: request processing, 1: error