node-libcurl
Version:
The fastest http(s) client (and much more) for Node.js - Node.js bindings for libcurl
202 lines (177 loc) • 4.21 kB
text/typescript
/**
* Copyright (c) Jonathan Cardoso Machado. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {
CurlOptionName,
CurlOptionCamelCaseMap,
CurlOptionValueType,
} from './generated/CurlOption'
import { HeaderInfo } from './parseHeaders'
import { Curl } from './Curl'
/**
* Object the curly call resolves to.
*
* @public
*/
export interface CurlyResult {
/**
* Data will be the body of the requested URL
*/
data: string
/**
* Parsed headers
*
* See {@link HeaderInfo}
*/
headers: HeaderInfo[]
/**
* HTTP Status code for the last request
*/
statusCode: number
}
// This is basically http.METHODS
const methods = [
'acl',
'bind',
'checkout',
'connect',
'copy',
'delete',
'get',
'head',
'link',
'lock',
'm-search',
'merge',
'mkactivity',
'mkcalendar',
'mkcol',
'move',
'notify',
'options',
'patch',
'post',
'propfind',
'proppatch',
'purge',
'put',
'rebind',
'report',
'search',
'source',
'subscribe',
'trace',
'unbind',
'unlink',
'unlock',
'unsubscribe',
] as const
type HttpMethod = typeof methods[number]
interface CurlyHttpMethodCall {
/**
* **EXPERIMENTAL** This API can change between minor releases
*
* Async wrapper around the Curl class.
*
* The `curly.<field>` being used will be the HTTP verb sent.
*/
(url: string, options?: CurlOptionValueType): Promise<CurlyResult>
}
type HttpMethodCalls = { [K in HttpMethod]: CurlyHttpMethodCall }
export interface CurlyFunction extends HttpMethodCalls {
/**
* **EXPERIMENTAL** This API can change between minor releases
*
* Async wrapper around the Curl class
* It's also possible to request using a specific http verb
* directly by using `curl.<http-verb>(url)`
*/
(url: string, options?: CurlOptionValueType): Promise<CurlyResult>
create: () => CurlyFunction
}
const create = (): CurlyFunction => {
function curly(
url: string,
options: CurlOptionValueType = {},
): Promise<CurlyResult> {
const curlHandle = new Curl()
curlHandle.setOpt('URL', url)
for (const key of Object.keys(options)) {
const keyTyped = key as keyof CurlOptionValueType
const optionName: CurlOptionName =
keyTyped in CurlOptionCamelCaseMap
? CurlOptionCamelCaseMap[
keyTyped as keyof typeof CurlOptionCamelCaseMap
]
: (keyTyped as CurlOptionName)
// @ts-ignore @TODO Try to type this
curlHandle.setOpt(optionName, options[key])
}
return new Promise((resolve, reject) => {
try {
curlHandle.on('end', (statusCode, data, headers) => {
curlHandle.close()
resolve({
statusCode: statusCode as number,
data: data as string,
headers: headers as HeaderInfo[],
})
})
curlHandle.on('error', (error, errorCode) => {
curlHandle.close()
// @ts-ignore
error.code = errorCode
reject(error)
})
curlHandle.perform()
} catch (error) {
curlHandle.close()
reject(error)
}
})
}
curly.create = create
const httpMethodOptionsMap: Record<
string,
null | ((m: string, o: CurlOptionValueType) => CurlOptionValueType)
> = {
get: null,
post: (_m, o) => ({
post: true,
...o,
}),
head: (_m, o) => ({
nobody: true,
...o,
}),
_: (m, o) => ({
customRequest: m,
...o,
}),
}
for (const httpMethod of methods) {
const httpMethodOptionsKey = httpMethodOptionsMap.hasOwnProperty(httpMethod)
? httpMethod
: '_'
const httpMethodOptions = httpMethodOptionsMap[httpMethodOptionsKey]
// @ts-ignore
curly[httpMethod] =
httpMethodOptions === null
? curly
: (url: string, options: CurlOptionValueType = {}) =>
curly(url, {
...httpMethodOptions(httpMethod, options),
})
}
// @ts-ignore
return curly
}
/**
* Curly function
*
* @public
*/
export const curly = create()