Skip to content

Instantly share code, notes, and snippets.

@alex-taxiera
Last active February 23, 2021 04:29
Show Gist options
  • Save alex-taxiera/98d9fc332746d2442e9d65c0ba487d49 to your computer and use it in GitHub Desktop.
Save alex-taxiera/98d9fc332746d2442e9d65c0ba487d49 to your computer and use it in GitHub Desktop.
node http request wrapper (JS and TS)
{
"name": "request",
"version": "1.0.0",
"main": "request.js"
}
import https from 'https'
import http from 'http'
import { URL } from 'url'
import zlib from 'zlib'
import FormData from 'form-data'
export const requesters = {
'http:': http,
'https:': https,
}
export const decompressors = {
deflate: zlib.createInflate,
gzip: zlib.createGunzip,
}
export default function request (
url,
options = {},
) {
const {
method = 'GET',
body,
timeout,
...reqOptions,
} = options
if (!http.METHODS.includes(method.toUpperCase())) {
return Promise.reject(Error(`INVALID METHOD: ${method.toUpperCase()}`))
}
const address = new URL(url)
const protocol = requesters[address.protocol]
if (!protocol) {
return Promise.reject(Error(`INVALID PROTOCOL: ${address.protocol}`))
}
return new Promise((resolve, reject) => {
const req = protocol.request(address, { ...reqOptions, method })
if (body) {
if (body instanceof FormData) {
body.pipe(req)
} else {
req.write(body)
req.end()
}
} else {
req.end()
}
if (timeout) {
req.setTimeout(timeout)
}
req
.once('error', reject)
.once('timeout', () => req.destroy(new Error('REQUEST TIMED OUT')))
.once('response', (res) => {
const chunks = []
const decompressor = decompressors[res.headers['content-encoding']]
const stream = decompressor ? res.pipe(decompressor()) : res
stream
.once('aborted', reject)
.once('error', reject)
.on('data', (chunk) => chunks.push(chunk))
.once('end', () => {
if (res.complete) {
resolve({
req, res, body: Buffer.concat(chunks),
})
} else {
reject(Error('REQUEST NOT COMPLETED'))
}
})
})
})
}
import https from 'https'
import http from 'http'
import { URL } from 'url'
import zlib from 'zlib'
import FormData from 'form-data'
export const requesters = {
'http:': http,
'https:': https,
}
export const decompressors = {
deflate: zlib.createInflate,
gzip: zlib.createGunzip,
}
export interface Response {
req: http.ClientRequest
res: http.IncomingMessage
body: Buffer
}
export interface Options extends http.RequestOptions {
body?: string | FormData
timeout?: number
}
export default function request (
url: string,
options: Options = {},
): Promise<Response> {
const {
method = 'GET',
body,
timeout,
...reqOptions,
} = options
if (!http.METHODS.includes(method.toUpperCase())) {
return Promise.reject(Error(`INVALID METHOD: ${method.toUpperCase()}`))
}
const address = new URL(url)
const protocol = requesters[address.protocol as keyof typeof requesters]
if (!protocol) {
return Promise.reject(Error(`INVALID PROTOCOL: ${address.protocol}`))
}
return new Promise((resolve, reject) => {
const req = protocol.request(address, { ...reqOptions, method })
if (body) {
if (body instanceof FormData) {
body.pipe(req)
} else {
req.write(body)
req.end()
}
} else {
req.end()
}
if (timeout) {
req.setTimeout(timeout)
}
req
.once('error', reject)
.once('timeout', () => req.destroy(new Error('REQUEST TIMED OUT')))
.once('response', (res) => {
const chunks: Array<Buffer> = []
const decompressor = decompressors[
res.headers['content-encoding'] as keyof typeof decompressors
]
const stream = decompressor ? res.pipe(decompressor()) : res
stream
.once('aborted', reject)
.once('error', reject)
.on('data', (chunk: Buffer) => chunks.push(chunk))
.once('end', () => {
if (res.complete) {
resolve({
req, res, body: Buffer.concat(chunks),
})
} else {
reject(Error('REQUEST NOT COMPLETED'))
}
})
})
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment