Search code examples
node.jsexpressmiddleware

NODEJS how to connect several express.method() via middleware


I have built , using express() , a variety of methods. for simplicity let's I assume I built 2 POST() functions and I want to be able to use them by themselves and also to concatenate them via middleware for combine usage.

app.post('/create_obj_1' , function (req,res) {
    //create Object_type_1
    // send Object_type_1 via EXTERNAL API to somewhere
    res.json({{ "statusCode": 200, "message": "OK" }
}
app.post('/create_obj_2' , function (req,res) {
    //create Object_type_2
    // send Object_type_2 via EXTERNAL API to somewhere
    res.json({{ "statusCode": 200, "message": "OK" }
}

I want to have a new POST() that can invoke both of the other 2 (but still support stand alone invoking of the original 2 I think it's possible via middleware but I am not sure how - this is how I thought the new POST() should look like -

app.post('/create_obj_all' , function (req,res) {
   //I want to invoke the create_obj_1 & create_obj_2 , check all OK, and finish
    res.json({{ "statusCode": 200, "message": "OK" }
}

I am not sure how to approach the middleware usage in such case.

On top - how can I connect them to use one each other res? let's say the EXTERNAL API returns some value from obj_1 creation which I want to use in obj_2 post() function..

a Pseudo code of my attempt to use request() inside the middlware_1 -

var middle_1 = function (req, res, next) {
        req.middle_1_output  = {
            statusCode : 404,
            message : "fail_1"
        }
        var options = { 
                method: 'PUT', url: `EXTERNAL_API`, headers: 
                { 
                    'cache-control': 'no-cache',
                    'content-type': 'application/x-www-form-urlencoded',
                    apikey: `KEY`
                }
            };
        request(options, function (error, response, body) {
            if (error) throw new Error(error);

            // CODE THAT DO SOMETHING AND GET INFORMATION

            // OLD WAY OF res.send here , to allow using in post.POST() was - res.status(200).send(body);

            //res.status(200).send(body);
            req.middle_1_output.statusCode = 200;
            req.middle_1_output.message = "hello world";
        });
     next(); // trigger next middleware
}

Solution

  • Given the current example, I don't think you can do it unless you tweak the middlewares for the first two routes a bit:

    var middleware1 = function(req, res, next) {
      //create Object_type_1
      // send Object_type_1 via EXTERNAL API to somewhere
    
      next(); // calling next() triggers the next middleware
    };
    
    var middleware2 = function(req, res, next) {
      //create Object_type_2
      // send Object_type_2 via EXTERNAL API to somewhere
    
      next(); // calling next() triggers the next middleware
    };
    
    /**
     * This middleware is only used to send success response
     */
    var response_success = function(req, res) {
    
        res.json({ "statusCode": 200, "message": "OK" });
    }
    
    app.post('/create_obj_1', middleware1, response_success);
    
    app.post('/create_obj_2', middleware2, response_success);
    
    app.post('/create_obj_all', middleware1, middleware2, response_success);
    

    Note that this is a very simplistic solution that I made from your example. The actual implementation will depend on what input each middleware is expecting and what output they generate. Also unlike here, there may also be different middlewares for sending the response.

    2nd Part Addressing the second part of your question, if I have got you correctly you want to pass the output from middleware1 to middleware2. You can simply attach the output to the req object before calling next();. Like so:

    var middleware1 = function(req, res, next) {
    
      // do something
    
      some_external_api_call(function(error, data) {
    
        if (error) {
          // handle the error yourself or call next(error);
        } else {
    
          req.middleware1_output = data; // set the output of the external api call into a property of req
          next();
        }
      });
    };
    
    var middleware2 = function(req, res, next) {
    
      // check to see if the middleware1_output has been set 
      // (meaning that the middleware has been called from /create_obj_all )
      if (req.middleware1_output) {
    
        // do something with the data
    
      } else {
    
        // handle scenario when /create_obj_2 is called by itself
    
      }
    
      next(); // calling next() triggers the next middleware
    };
    

    Notice how you have to account for both scenarios where middleware2 is called from POST /create_obj_all or directly from POST /create_obj_2.

    3rd Part You should call next from within the callback. See my above example. This is due to the asynchronous/non-blocking nature of javascript.

    function middleware(req, res, next) {
    
        // do something
    
        call_1st_external_api(some_options, function(error, data) {
    
            // executed after call_1st_external_api completes
    
            req.output_of_1st_external_api = data; // store the data of this api call for access from next middleware
    
            next(); // calls the next middleware
    
            // nothing here will be executed as next has already been called
        });
    
        // anything here will be executed before call_1st_external_api is completed
        next(); // this will call the next middleware before call_1st_external_api completes
    }
    

    To handle two external APIs in the same middlewares you have to nest them (or use async or promises):

    function middleware(req, res, next) {
    
        // do something
    
        call_1st_external_api(some_options, function(error1, data1) {
    
            // executed after call_1st_external_api completes
    
            req.output_of_1st_external_api = data1; // store the data of this api call for access from next middleware
    
            // executed after call_2nd_external_api completes
    
            call_2nd_external_api(some_options, function(error2, data2) {
    
                req.output_of_2nd_external_api = data2; // store the data of this api call for access from next middleware
    
                next();
            });
    
            // anything here will be executed before call_2nd_external_api is completed
        });
    
        // anything here will be executed before call_1st_external_api is completed
    }
    

    You have to handle all the errors above like I've shown in the 2nd Part which I have not shown in the above example for the sake of simplicity.