Last active
March 24, 2022 06:54
-
-
Save jeremybradbury/cf049bf7aa6447e284bf07c923601c0d to your computer and use it in GitHub Desktop.
a JS wrapper for NodeJS http/s Request, supports json & forms via post body
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// written for NodeJS v12 | |
const https = require("https"); // core node | |
const http = require("http"); // core node | |
const qs = require("querystring"); // core node | |
const isProd = process.env.NODE_ENV === "production"; | |
const debug = process.env.DEBUG; | |
const request = async ( | |
url = "", // string | |
options = {}, // any, or see: https://nodejs.org/api/http.html#new-agentoptions | |
postData = null, // null | string | |
onEnd = (data) => Buffer.concat(data).toString(), // (data:array) => string | Buffer | Buffer[] | |
onData = (chunk, data) => [...data, chunk] // (chunk: string | Buffer, data: string[] | Buffer[]) => string[] | Buffer[] | |
) => { | |
// handle https callouts the proper way | |
options.method = options.method || (postData && "POST" || "GET"); // method is optional, even if options were provided | |
options.headers = options.headers || {}; // headers are optional, even if options were provided | |
// json when not specified | |
if (! options.headers["Content-Type"]) | |
options.headers["Content-Type"] = "application/json"; | |
// handle uploads and forms | |
if (options.headers["Content-Type"] === "application/x-www-form-urlencoded" ) | |
postData = postData ? qs.stringify(postData) : null; // form body or null | |
else postData = postData ? JSON.stringify(postData) : null; // json body or null | |
// handle local requests without config | |
const httpx = url.startsWith('https') ? https : http; // inline require (one not both) is fast with binary modules at execution time but CJS only | |
// handle debugging | |
if (!isProd) console.debug("request url: ", {url, options}); | |
if (!isProd && debug) console.debug({postData}, "\n", {onEnd}, "\n", {onData}); | |
return new Promise((resolve, reject) => { | |
const req = httpx.request(url, options, (res) => { // class extends Stream interface: https://nodejs.org/api/http.html#class-httpclientrequest | |
let data = []; | |
res.on("data", (chunk) => onData(chunk, data)); // this could also handle a stream | |
res.on("end", () => { | |
const final = onEnd(data); // this could also handle a stream | |
if (res.statusCode < 200 || res.statusCode >= 300) { | |
const parsed = typeof final === string ? JSON.parse(final) : final; // don't fail on non-string handlers | |
// construct a human readable error message to log and / or respond with | |
reject(`request(${options.method}): ${res.statusCode} ` + url.split("?")[0]} | |
+ " " + parsed?.error | |
? parsed.error + " : " parsed.message | |
: JSON.stringify(final) | |
); // note: printing a stack here on response errors isn't helpful | |
} else { | |
resolve(final); // return response body as a string (or however you formatted it) | |
} | |
}); | |
}); | |
req.on("error", (err) => | |
reject(`request(${options.method}): ${err.message}`)); // use try/catch in your implementation | |
if (postData) { | |
req.write(postData); // send the post body text | |
} | |
req.end(); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment