Victor Molina
Victor Molina

Reputation: 2641

How to handle HTTPs json format errors from APIs in Node.js?

INTRODUCTION

I am implementing a function for making any kind of https request to any endpoint (using the https native module). When I make a request to a specific API I get an error response in JSON format. Like this:

{
    "error": {
        "code": 404,
        "message": "ID not found"
     }
}

How can I handle this kind of errors? At a first moment, I supposed that they were handled in

request.on("error", (err) => { reject(err); });

HTTPs Request function code

I have comment '<---------' in the relevant parts of the code

const https = require("https");

exports.httpsRequest = function (options, body = null) {
  /* 
    This function is useful for making requests over the HTTPs protocol 
   */

  return new Promise((resolve, reject) => {
    const request = https.request(options, (response) => {
      // Get the response content type
      const contentType =
        response.headers["content-type"] &&
        response.headers["content-type"].split(";")[0];

      // Cumulate data
      let chuncks = [];
      response.on("data", (chunck) => {
        chuncks.push(chunck);
      });

      response.on("end", () => {
        // Concat all received chunks
        let response = Buffer.concat(chuncks);

        // Some responses might be in JSON format...
        if (contentType === "application/json") {
          // Jsonify the response
          response = JSON.parse(response);
        }

        // (For the future) TODO - Check and parse more content types if needed.

        // Resolve the promise with the HTTPs response
        resolve(response); // <--------- The JSON format error responses are resolved too!!
      });
    });

    // Reject on request error
    request.on("error", (err) => {
      // <------------- At a first moment, I supposed that all error responses were handled in this part of the code
      reject(err);
    });

    // Write the body
    if (body) {
      request.write(body);
    }

    // Close HTTPs connection.
    request.end();
  });
};

Question

Why the error response is not handled in request.on("error", ...) ?

Thank you. I would appreciate any help or suggestion.

Upvotes: 1

Views: 1322

Answers (1)

jfriend00
jfriend00

Reputation: 707476

You need to create a different code path for when the content type isn't what you were expecting in which you call reject() and you also need to try/catch around JSON parsing errors so you can properly catch them and reject on them too. You can solve those issues with this code:

exports.httpsRequest = function (options, body = null) {
  /* 
    This function is useful for making requests over the HTTPs protocol 
   */

  return new Promise((resolve, reject) => {
    const request = https.request(options, (response) => {
      // Get the response content type
      const contentType =
        response.headers["content-type"] &&
        response.headers["content-type"].split(";")[0];

      // Cumulate data
      let chuncks = [];
      response.on("data", (chunck) => {
        chuncks.push(chunck);
      });

      response.on("end", () => {
        // Concat all received chunks
        let response = Buffer.concat(chuncks);

        // Some responses might be in JSON format...
        if (contentType === "application/json") {
            try {
              // Jsonify the response
              response = JSON.parse(response);
              resolve(response);
              return;
            } catch(e) {
              reject(e);
              return;
            }
        }
        reject(new Error("Not JSON content-type"))
      });
    });

    // Reject on request error
    request.on("error", (err) => {
      reject(err);
    });

    // Write the body
    if (body) {
      request.write(body);
    }

    // Close HTTPs connection.
    request.end();
  });
};

FYI, libraries such as got() and others listed here, all do this work for you automatically and have a lot of other useful features. You don't really need to build this yourself.

Upvotes: 1

Related Questions