Skip to content

Instantly share code, notes, and snippets.

@maletor
Created November 3, 2020 16:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maletor/1028d89c5016d19facd51711637f1700 to your computer and use it in GitHub Desktop.
Save maletor/1028d89c5016d19facd51711637f1700 to your computer and use it in GitHub Desktop.
Generic HTTP methods
import { IncomingMessage } from "http";
import { Agent, request, RequestOptions } from "https";
const agent = new Agent({ keepAlive: true, timeout: 10000 });
class MissingStatusCodeError extends Error {
constructor(public url: string) {
super("Missing a status code");
this.name = "MissingStatusCodeError";
this.url = url;
}
}
class TimeoutError extends Error {
constructor(public url: string) {
super("Timeout error");
this.name = "TimeoutError";
this.url = url;
}
}
export class ClientError extends Error {
constructor(
public url: RequestInfo,
public status: number,
public response?: unknown
) {
super("Client error");
this.name = "ClientError";
this.url = url;
this.status = status;
this.response = response;
}
}
class ServerError extends Error {
constructor(
public url: RequestInfo,
public status: number,
public response?: unknown
) {
super("Server error");
this.name = "ServerError";
this.url = url;
this.status = status;
this.response = response;
}
}
const parseIncoming = (incoming: IncomingMessage): Promise<unknown> =>
new Promise((resolve, reject) => {
const data: Buffer[] = [];
incoming.on("data", (chunk) => data.push(chunk));
incoming.on("end", () => {
try {
const response = Buffer.concat(data).toString();
const json: unknown = JSON.parse(response);
resolve(json);
} catch (error) {
reject(error);
}
});
});
const makeRequest = (
url: string,
options: RequestOptions,
method: "GET" | "POST",
data?: string
): Promise<IncomingMessage> =>
new Promise((resolve, reject) => {
const req = request(url, { ...options, method, agent }, (incoming) => {
const statusCode = incoming.statusCode;
if (!statusCode) return reject(new MissingStatusCodeError(url));
if (statusCode >= 400 && statusCode < 500) {
parseIncoming(incoming)
.then((json) => reject(new ClientError(url, statusCode, json)))
.catch(() => reject(new ClientError(url, statusCode)));
return;
}
if (statusCode >= 500 && statusCode < 600) {
parseIncoming(incoming)
.then((json) => reject(new ServerError(url, statusCode, json)))
.catch(() => reject(new ServerError(url, statusCode)));
return;
}
resolve(incoming);
});
req.on("error", (error) => reject(error));
req.on("timeout", () => req.destroy(new TimeoutError(url)));
if (data) req.write(data);
req.end();
});
const getStream = (
url: string,
options: RequestOptions
): Promise<IncomingMessage> => makeRequest(url, options, "GET");
export const get = (url: string, options: RequestOptions): Promise<unknown> =>
getStream(url, options).then(parseIncoming);
const postStream = (
url: string,
options: RequestOptions,
data?: string
): Promise<IncomingMessage> => makeRequest(url, options, "POST", data);
export const post = (
url: string,
options: RequestOptions,
data?: string
): Promise<unknown> => postStream(url, options, data).then(parseIncoming);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment