Arjun Chaudhary
Arjun Chaudhary

Reputation: 2453

Extracting the common code of handling response from callback function

In the below code, I can extract the response handling code and place it in a different callback function and then pass the name of the callback function. However, I won't be able to do it because from within the code I have to return a response with a message and status code, and hence the code is tightly coupled with the res variable. I am not able to refactor this code such that I can take out the response handling code to a separate function and then can use it for other post calls. Is there any coding pattern to achieve it?

function saveCompany(req, res) {
    let headers = req.headers;
    let url = req.url;
    request.post(
        {
            uri: url,
            headers: {
                "content-type": "application/json",
                Authorization: headers.authorization
            },
            json: true,
            body: req.body
        },
        (error, response, body) => {
            if (error) {
                return res.status(response.statusCode).send(error)
            }

            // I don't know if the 3xx responses come here, if so you'll want to handle them appropriately
            if (response.statusCode < 200 || response.statusCode >= 300) {
                return res.status(response.statusCode).send({
                    message: 'Error while getting result.'
                 });
            }

            let bodyData = response ? response.body : response;
            return res.send(bodyData);
        }
}

Upvotes: 0

Views: 408

Answers (2)

Ethan Lipkind
Ethan Lipkind

Reputation: 1156

you can pass res as an argument to the callback function, in addition to error, response, and body which are passed already. then you would be able to do something like this:

function saveCompany(req, res) {
    let headers = req.headers;
    let url = req.url;
    request.post(
        {
            uri: url,
            headers: {
                "content-type": "application/json",
                Authorization: headers.authorization
            },
            json: true,
            body: req.body
        },
        (error, response, body) => cb(error, response, body, res))
}

const cb = (error, response, body, res) => {
  if (error) {
                return res.status(response.statusCode).send(error)
            }

            // I don't know if the 3xx responses come here, if so you'll want to handle them appropriately
            if (response.statusCode < 200 || response.statusCode >= 300) {
                return res.status(response.statusCode).send({
                    message: 'Error while getting result.'
                 });
            }

            let bodyData = response ? response.body : response;
            return res.send(bodyData);
}

Upvotes: 2

Kalesh Kaladharan
Kalesh Kaladharan

Reputation: 1058

The pattern I use for my external API request handler is given below.

/**
 * Request handler function.
 *
 * @param {*} uri
 * @param {*} body
 * @param {*} headers
 * @param {*} onSuccess
 * @param {*} onError
 */
function reqHandler(uri, body, headers, onSuccess, onError) {
    request.post(
        {
            uri,
            headers,
            body,
            json: true,
        },
        (error, response) => {
            if (error) {
                return typeof onError === 'function' && onError(error, response);
            }
            // Call the error handler with message.
            if (response.statusCode < 200 || response.statusCode >= 300) {
                return (
                    typeof onError === 'function' &&
                    onError(error, response, 'Error while getting message.')
                );
            }
            // Call the success handler with the response.
            return typeof onSuccess === 'function' && onSuccess(response);
        },
    );
}

/**
 * Your controller function.
 *
 * @param {*} req
 * @param {*} res
 */
function saveCompany(req, res) {
    const onSuccess = (response) => {
        let bodyData = response ? response.body : response;
        return res.send(bodyData);
    };

    const onError = (error, response, message) => {
        return res.status(response.statusCode).send(message || error);
    };

    // Initiate the request.
    reqHandler(req.url, req.body, req.headers, onSuccess, onError);
}

With this design, reqHandler does not care about req and res. It just takes the parameters it needs for making an external API request. If callback functions are given, the reqHandler executes them when appropriate.

Your controller code should execute the reqHandler function passing the necessary parameters including the success/error handler functions.

One issue with this design is the need to create an onSuccess and onError callback function on every controller that needs to make a request. If the success/error handler is going to have the same definition for all the requests, then you should extend the res class/object to include these functions and pass them to the reqHandler

Upvotes: 0

Related Questions