{"id":22930200,"url":"https://github.com/jhuckaby/pixl-request","last_synced_at":"2025-08-12T15:31:10.505Z","repository":{"id":36085720,"uuid":"40386438","full_name":"jhuckaby/pixl-request","owner":"jhuckaby","description":"A very simple module for making HTTP requests.","archived":false,"fork":false,"pushed_at":"2024-10-23T22:46:36.000Z","size":183,"stargazers_count":3,"open_issues_count":2,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-24T09:04:36.456Z","etag":null,"topics":["http","https","json","json-api","request","xml"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jhuckaby.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-08-08T00:41:12.000Z","updated_at":"2024-10-23T22:46:26.000Z","dependencies_parsed_at":"2024-03-26T20:31:58.146Z","dependency_job_id":"f7d62822-4da8-40e3-8297-31cf4f6cf587","html_url":"https://github.com/jhuckaby/pixl-request","commit_stats":{"total_commits":46,"total_committers":1,"mean_commits":46.0,"dds":0.0,"last_synced_commit":"9236c266abb862ae2441a61c2fbb0d4edd3d6517"},"previous_names":[],"tags_count":49,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhuckaby%2Fpixl-request","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhuckaby%2Fpixl-request/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhuckaby%2Fpixl-request/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhuckaby%2Fpixl-request/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jhuckaby","download_url":"https://codeload.github.com/jhuckaby/pixl-request/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229693631,"owners_count":18108879,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http","https","json","json-api","request","xml"],"created_at":"2024-12-14T10:26:55.216Z","updated_at":"2025-08-12T15:31:10.121Z","avatar_url":"https://github.com/jhuckaby.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Overview\n\nThis module is a very simple wrapper around Node's built-in [http](https://nodejs.org/api/http.html) library for making HTTP requests.  It provides an easy way to send an HTTP GET or POST, including things like support for HTTPS (SSL), file uploads and JSON REST style API calls.  Compressed responses are also handled automatically.\n\n# Table of Contents\n\n\u003c!-- toc --\u003e\n- [Usage](#usage)\n- [Method List](#method-list)\n- [Request Types](#request-types)\n\t* [HTTP GET](#http-get)\n\t* [HTTP HEAD](#http-head)\n\t* [HTTP POST](#http-post)\n\t\t+ [Pure Data POST](#pure-data-post)\n\t\t+ [Multipart POST](#multipart-post)\n\t\t+ [File Uploads](#file-uploads)\n\t* [HTTP PUT](#http-put)\n\t* [HTTP DELETE](#http-delete)\n\t* [File Downloads](#file-downloads)\n\t\t+ [Advanced Stream Control](#advanced-stream-control)\n\t* [Progress Updates](#progress-updates)\n\t* [Keep-Alives](#keep-alives)\n\t* [JSON REST API](#json-rest-api)\n\t* [XML REST API](#xml-rest-api)\n- [Default Headers](#default-headers)\n- [Handling Timeouts](#handling-timeouts)\n- [Automatic Redirects](#automatic-redirects)\n- [Automatic Errors](#automatic-errors)\n- [Automatic Retries](#automatic-retries)\n- [Compressed Responses](#compressed-responses)\n- [Abort Signals](#abort-signals)\n- [Performance Metrics](#performance-metrics)\n- [DNS Caching](#dns-caching)\n\t* [Flushing the Cache](#flushing-the-cache)\n- [SSL Certificate Validation](#ssl-certificate-validation)\n- [Proxy Servers](#proxy-servers)\n- [License](#license)\n\n# Usage\n\nUse [npm](https://www.npmjs.com/) to install the module:\n\n```\nnpm install pixl-request\n```\n\nThen use `require()` to load it in your code:\n\n```js\nconst PixlRequest = require('pixl-request');\n```\n\nInstantiate a request object and pass in an optional user agent string (you can also set this later via a header):\n\n```js\nlet request = new PixlRequest( \"My Custom Agent 1.0\" );\n```\n\nHere is a simple HTTP GET example:\n\n```js\ntry {\n\tlet { data } = await request.get('https://www.bitstamp.net/api/ticker/');\n\tconsole.log(\"Success: \" + data);\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\nThe result object actually contains other properties besides `data`.  Here is an example using all of them:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.get('https://www.bitstamp.net/api/ticker/');\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.get( 'https://www.bitstamp.net/api/ticker/', function(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nAnd here is a simple JSON REST API request:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.json('http://myserver.com/api', { \n\t\t\"foo\": \"test\", \n\t\t\"bar\": 123 \n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.json( 'http://myserver.com/api', { \"foo\": \"test\", \"bar\": 123 }, function(err, resp, data, perf) {\n\tif (err) throw(err);\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\n# Method List\n\nHere are all the methods available in the request library:\n\n| Method Name | Description |\n|---------------|-------------|\n| [get()](#http-get) | Performs an HTTP GET request. |\n| [head()](#http-head) | Performs an HTTP HEAD request. |\n| [post()](#http-post) | Performs an HTTP POST request. |\n| [put()](#http-put) | Performs an HTTP PUT request. |\n| [delete()](#http-delete) | Performs an HTTP DELETE request. |\n| [json()](#json-rest-api) | Sends a request to a JSON REST API endpoint and parses the response. |\n| [xml()](#xml-rest-api) | Sends a request to an XML REST API endpoint and parses the response. |\n| [setHeader()](#default-headers) | Overrides or adds a default header for future requests. |\n| [setTimeout()](#handling-timeouts) | Overrides the default socket timeout (milliseconds). |\n| [setFollow()](#automatic-redirects) | Overrides the default behavior for following redirects. |\n| [setAutoDecompress()](#compressed-responses) | Overrides the default behavior of decompressing responses. |\n| [setDNSCache()](#dns-caching) | Enable DNS caching and set the TTL in seconds. |\n| [flushDNSCache()](#flushing-the-cache) | Flush all IPs from the internal DNS cache. |\n\n# Request Types\n\nHere are all the request types supported by the library.\n\n## HTTP GET\n\n```\nPROMISE request.get( URL );\nPROMISE request.get( URL, OPTIONS );\n```\n\nTo perform a simple HTTP GET, call the `get()` method.  All you need to provide is the URL, and the result is an object containing the response (headers and such), data (as a buffer), and performance data:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.get('https://www.bitstamp.net/api/ticker/');\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.get( 'https://www.bitstamp.net/api/ticker/', function(err, resp, data, perf) {\n\tif (err) throw(err);\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nThe result of the operation is an object containing the HTTP response object from Node ([IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)), a data buffer of the content (if any), and a [performance tracker](#performance-metrics).\n\nWith async or promise usage, if an error occurs it is thrown.  Note that an \"error\" in this case is something like a TCP connection failure, DNS lookup failure, socket timeout, connection aborted, or other internal client library failure.  By default, HTTP response codes like 404 or 500 are *not* considered errors, so make sure to look at `resp.statusCode` if you are expecting an HTTP 200.  However, if you *want* non-200 response codes to be considered errors, see [Automatic Errors](#automatic-errors) below.\n\nTo specify additional options, such as custom request headers or HTTP authentication, include an object after the URL:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.get( 'https://www.bitstamp.net/api/ticker/', {\n\t\t\"headers\": {\n\t\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t\t},\n\t\t\"auth\": \"username:password\"\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.get( 'https://www.bitstamp.net/api/ticker/', {\n\t\"headers\": {\n\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t},\n\t\"auth\": \"username:password\"\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nCheck out the Node [http.request()](https://nodejs.org/api/http.html#httprequesturl-options-callback) documentation for all the properties you can pass in the options object.\n\nBy default, connections are closed at the end of each request.  If you want to reuse a persistent connection across multiple requests, see the [Keep-Alives](#keep-alives) section below.\n\n## HTTP HEAD\n\n```\nPROMISE request.head( URL )\nPROMISE request.head( URL, OPTIONS )\n```\n\nAn HTTP HEAD request will not contain any data in the response, only the response code and headers.  Example:\n\n```js\ntry {\n\tlet { resp, perf } = await request.head( 'http://myserver.com/index.html' );\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.head( 'http://myserver.com/index.html', function(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\n## HTTP POST\n\n```\nPROMISE request.post( URL, OPTIONS )\n```\n\nTo perform a HTTP POST, call the `post()` method.  Provide a URL, and an options object with a `data` property containing your key/value pairs:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/post', {\n\t\t\"data\": {\n\t\t\t\"full_name\": \"Fred Smith\", \n\t\t\t\"gender\": \"male\",\n\t\t\t\"age\": 35\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.post( 'http://myserver.com/api/post', {\n\t\"data\": {\n\t\t\"full_name\": \"Fred Smith\", \n\t\t\"gender\": \"male\",\n\t\t\"age\": 35\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nYour key/value pairs will be serialized using the `application/x-www-form-urlencoded` format.  For a multipart post, see [Multipart POST](#multipart-post) below.\n\nThe result of the operation is an object containing the HTTP response object from Node ([IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)), a data buffer of the content (if any), and a [performance tracker](#performance-metrics).\n\nWith async or promise usage, if an error occurs it is thrown.  Note that an \"error\" in this case is something like a TCP connection failure, DNS lookup failure, socket timeout, connection aborted, or other internal client library failure.  By default, HTTP response codes like 404 or 500 are *not* considered errors, so make sure to look at `resp.statusCode` if you are expecting an HTTP 200.  However, if you *want* non-200 response codes to be considered errors, see [Automatic Errors](#automatic-errors) below.\n\nCheck out the Node [http.request()](https://nodejs.org/api/http.html#httprequesturl-options-callback) documentation for all the properties you can pass in the options object.\n\nBy default, connections are closed at the end of each request.  If you want to reuse a persistent connection across multiple requests, see the [Keep-Alives](#keep-alives) section below.\n\n### Pure Data POST\n\nTo specify your own raw POST data without any key/value pre-formatting, simply pass a `Buffer` object as the `data` property value, then include your own `Content-Type` header in the `headers` object.  Example:\n\n```js\nlet buf = Buffer.from(\"VGhpcyBpcyBhIHRlc3QhIPCfmJw=\", \"base64\");\n\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/post', {\n\t\t\"data\": buf,\n\t\t\"headers\": {\n\t\t\t\"Content-Type\": \"application/octet-stream\"\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet buf = Buffer.from(\"VGhpcyBpcyBhIHRlc3QhIPCfmJw=\", \"base64\");\n\nrequest.post( 'http://myserver.com/api/post', {\n\t\"data\": buf,\n\t\"headers\": {\n\t\t\"Content-Type\": \"application/octet-stream\"\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\n### Multipart POST\n\nFor a `multipart/form-data` post, which is typically better for binary data, all you need to do is pass in a `multipart` property in your options object, and set it to a true value.  Everything else is the same as a standard [HTTP POST](#http-post):\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/post', {\n\t\t\"multipart\": true, // activate multipart/form-data\n\t\t\"data\": {\n\t\t\t\"foo\": Buffer.from(\"Joe was here!\"), \n\t\t\t\"bar\": 54321\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.post( 'http://myserver.com/api/post', {\n\t\"multipart\": true, // activate multipart/form-data\n\t\"data\": {\n\t\t\"foo\": Buffer.from(\"Joe was here!\"), \n\t\t\"bar\": 54321\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nNote that you can use [Buffer](https://nodejs.org/api/buffer.html) objects instead of strings for your data values.\n\n### File Uploads\n\nTo upload files, use `post()` and include a `files` object with your options, containing key/pair pairs.  Each file needs an identifier key (POST field name), and a value which should be a path to the file on disk:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/upload', {\n\t\t\"files\": {\n\t\t\t\"kitten1\": \"/images/SillyKitten1.jpg\",\n\t\t\t\"kitten2\": \"/images/SillyKitten2.jpg\"\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.post( 'http://myserver.com/api/upload', {\n\t\"files\": {\n\t\t\"kitten1\": \"/images/SillyKitten1.jpg\",\n\t\t\"kitten2\": \"/images/SillyKitten2.jpg\"\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nThe file path can also be a readable stream, if you happen to have one of those already open:\n\n```js\nlet stream = fs.createReadStream('/images/SillyKitten1.jpg');\n\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/upload', {\n\t\t\"files\": {\n\t\t\t\"file1\": stream\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet stream = fs.createReadStream('/images/SillyKitten1.jpg');\n\nrequest.post( 'http://myserver.com/api/upload', {\n\t\"files\": {\n\t\t\"file1\": stream\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nIf you want to customize the filename of the uploaded file, set your file value to an array, with the first element containing the file path (or a stream), and the second element the desired filename:\n\n```js\n\"files\": {\n\t\"file1\": [\"/images/SillyKitten1.jpg\", \"A-New-Filename.JPG\"]\n}\n```\n\nYou can combine file uploads with other POST data fields, just by including a `data` property in your options, similar to a standard HTTP POST.  You can of course include any other options keys as well, such as custom headers:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/post', {\n\t\t\"files\": {\n\t\t\t\"file1\": \"/images/SillyKitten1.jpg\"\n\t\t},\n\t\t\"data\": {\n\t\t\t\"foo\": Buffer.from(\"Joe was here!\"), \n\t\t\t\"bar\": 54321\n\t\t},\n\t\t\"headers\": {\n\t\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.post( 'http://myserver.com/api/post', {\n\t\"files\": {\n\t\t\"file1\": \"/images/SillyKitten1.jpg\"\n\t},\n\t\"data\": {\n\t\t\"foo\": Buffer.from(\"Joe was here!\"), \n\t\t\"bar\": 54321\n\t},\n\t\"headers\": {\n\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nIncluding a `files` property automatically sets `multipart/form-data` mode, so you don't need to include the `multipart` boolean flag in this case.\n\n## HTTP PUT\n\n```\nPROMISE request.put( URL, OPTIONS )\n```\n\nTo send an `HTTP PUT`, you can use the `put()` method.  This works identically to `post()` in every way, except that the HTTP method is changed from `POST` to `PUT`.  You can send all the various data types, upload files, etc.  Example:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.put( 'http://myserver.com/api/put', {\n\t\t\"data\": {\n\t\t\t\"full_name\": \"Fred Smith\", \n\t\t\t\"gender\": \"male\",\n\t\t\t\"age\": 35\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.put( 'http://myserver.com/api/put', {\n\t\"data\": {\n\t\t\"full_name\": \"Fred Smith\", \n\t\t\"gender\": \"male\",\n\t\t\"age\": 35\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nNote that data (i.e. request body) is optional, and can be omitted.\n\n## HTTP DELETE\n\n```\nPROMISE request.delete( URL, OPTIONS )\n```\n\nTo send an `HTTP DELETE`, you can use the `delete()` method.  This works identically to `post()` in every way, except that the HTTP method is changed from `POST` to `DELETE`.  You can send all the various data types, upload files, etc.  Example:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.delete( 'http://myserver.com/api/delete', {\n\t\t\"data\": {\n\t\t\t\"username\": \"fsmith\"\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.delete( 'http://myserver.com/api/delete', {\n\t\"data\": {\n\t\t\"username\": \"fsmith\"\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nNote that data (i.e. request body) is optional, and can be omitted.\n\n## File Downloads\n\nIf you want to download the response data to a file, instead of loading it all into an in-memory Buffer object, you can specify a `download` property in your `options` object, passed to either `get()` or `post()`.  Set this property to a filesystem path, and a file will be created and written to.  Example:\n\n```js\ntry {\n\tlet { resp, perf } = await request.get( 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Gustav_chocolate.jpg', {\n\t\t\"download\": \"/var/tmp/myimage.jpg\"\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.get( 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Gustav_chocolate.jpg', {\n\t\"download\": \"/var/tmp/myimage.jpg\"\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nThe promise will only be resolved when the file is *completely* downloaded and written to the stream.  If the response is encoded (compressed), this is handled transparently for you using an intermediate stream.  Your file will contain the final decompressed data, and no memory will be used.\n\nAlternatively, if you already have an open writable stream object, you can pass that to the `download` property.  Example:\n\n```js\nlet stream = fs.createWriteStream( '/var/tmp/myimage.jpg' );\n\ntry {\n\tlet { resp, perf } = await request.get( 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Gustav_chocolate.jpg', {\n\t\t\"download\": stream\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet stream = fs.createWriteStream( '/var/tmp/myimage.jpg' );\n\nrequest.get( 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Gustav_chocolate.jpg', {\n\t\"download\": stream\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\n### Advanced Stream Control\n\nIf you need more control over the response stream, you can provide a `preflight` property in your `options` object, passed to either `get()` or `post()`.  Set this property to a callback function, which will be called *before* the data is downloaded, but *after* the HTTP response headers are parsed.  This allows you to essentially intercept the response and set up your own stream pipe.  Example:\n\n```js\nlet stream = fs.createWriteStream( '/var/tmp/myimage.jpg' );\n\ntry {\n\tlet { resp, perf } = await request.get( 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Gustav_chocolate.jpg', {\n\t\t\"download\": stream,\n\t\t\"preflight\": function(err, resp) {\n\t\t\t// setup stream pipe ourselves\n\t\t\tresp.pipe( stream );\n\t\t\treturn true;\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet stream = fs.createWriteStream( '/var/tmp/myimage.jpg' );\n\nrequest.get( 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Gustav_chocolate.jpg', {\n\t\"download\": stream,\n\t\"preflight\": function(err, resp) {\n\t\t// setup stream pipe ourselves\n\t\tresp.pipe( stream );\n\t\treturn true;\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + \" \" + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nYour `preflight` function can optionally return `false`, which will inform the library that you did not set up a stream pipe, and it should resolve the promise with a data buffer instead.\n\n## Progress Updates\n\nIf you would like to receive progress updates during a file download or large data transfer, add a `progress` property to your options object, and set it to a callback function.  Your function will be called repeatedly during the data transfer, and be passed the current data chunk as a buffer, and the HTTP response object from Node ([IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)).  Example use:\n\n```js\ntry {\n\tlet { resp, perf } = await request.get( 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Gustav_chocolate.jpg', {\n\t\t\"download\": \"/var/tmp/myimage.jpg\"\n\t\t\"progress\": function(chunk, resp) {\n\t\t\t// called repeatedly during download\n\t\t\tconsole.log( \"Got chunk, \" + chunk.length + \" bytes\" );\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.get( 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Gustav_chocolate.jpg', {\n\t\"download\": \"/var/tmp/myimage.jpg\",\n\t\"progress\": function(chunk, resp) {\n\t\t\t// called continuously during download\n\t\t\tconsole.log( \"Got chunk, \" + chunk.length + \" bytes of \" + resp.headers['content-length'] );\n\t\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nNote that progress events only fire on data *received* (i.e. downloaded).\n\n## Keep-Alives\n\nTo reuse the same socket connection across multiple requests, you have two options.  First, you can use the built-in Keep-Alive handler by calling the `setKeepAlive()` method and passing `true`.  Example:\n\n```js\nrequest.setKeepAlive( true );\n```\n\nThis will attempt to use HTTP Keep-Alives for all HTTP and HTTPS requests, by using two global [http.Agent](https://nodejs.org/api/http.html#class-httpagent) objects (one per protocol).  Note that you can configure the options passed to the agents by specifying them as a secondary object to the `setKeepAlive()` method:\n\n```js\nrequest.setKeepAlive( true, {\n\tkeepAlive: true,\n\tkeepAliveMsecs: 1000,\n\tmaxSockets: 256,\n\tmaxFreeSockets: 256,\n\ttimeout: 5000\n} );\n```\n\nAlternatively, you can use your own [http.Agent](https://nodejs.org/api/http.html#class-httpagent) object (provided by Node).  Simply construct an instance, set the `keepAlive` property to `true`, and pass it into the options object for your requests, using the `agent` property:\n\n```js\nlet http = require('http');\nlet agent = new http.Agent({ keepAlive: true });\n\ntry {\n\tlet { resp, data, perf } = await request.get( 'http://myserver.com/api/get', {\n\t\t\"agent\": agent, // custom agent for connection pooling\n\t\t\"headers\": {\n\t\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet http = require('http');\nlet agent = new http.Agent({ keepAlive: true });\n\nrequest.get( 'http://myserver.com/api/get', {\n\t\"agent\": agent, // custom agent for connection pooling\n\t\"headers\": {\n\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nYou can then use the same `agent` object for subsequent requests on the same host (provided the server you are connecting to also supports Keep-Alives).\n\n## JSON REST API\n\n```\nPROMISE request.json( URL, JSON )\nPROMISE request.json( URL, JSON, OPTIONS )\n```\n\nThe `json()` method is designed for sending requests to JSON REST APIs.  If you want to send a JSON REST style HTTP POST to an API endpoint, and expect to receive a JSON formatted response, this wraps up all the serialization and parsing for you.  Example:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.json( 'http://myserver.com/api', { \n\t\t\"foo\": \"test\", \n\t\t\"bar\": 123 \n\t} );\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.json( 'http://myserver.com/api', { \"foo\": \"test\", \"bar\": 123 }, function(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nThis will serialize the object into a JSON string, and send it as the HTTP POST data to the provided URL, with a Content-Type of `application/json`.  It also expects the response back from the server to be JSON, and will parse it for you.  The result will contain the HTTP response object ([IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)), the parsed JSON object, and a [performance tracker](#performance-metrics).\n\nYou can also specify options such as custom request headers using this API.  Simply include an options object as the final argument (similar to the `get()` and `post()` methods).  Example:\n\n```js\nlet json = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\ntry {\n\tlet { resp, data, perf } = await request.json( 'http://myserver.com/api', json, {\n\t\t\"headers\": {\n\t\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet json = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\nrequest.json( 'http://myserver.com/api', json, {\n\t\"headers\": {\n\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nIf you pass `null` or `false` as the JSON data argument, the request will be sent as a `GET` instead of a `POST`.  You can also customize the HTTP method by passing a `method` property into the `options` object.  For example, the following would send as a `HTTP PUT` with the JSON serialized in the request body:\n\n```js\nlet json = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\ntry {\n\tlet { resp, data, perf } = await request.json( 'http://myserver.com/api', json, {\n\t\t\"method\": \"PUT\", // override the default method here\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet json = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\nrequest.json( 'http://myserver.com/api', json, {\n\t\"method\": \"PUT\", // override the default method here\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nYou can also send a custom request method with no body:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.json( 'http://myserver.com/delete/user/345', false, {\n\t\t\"method\": \"DELETE\", // override the default method here\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.json( 'http://myserver.com/delete/user/345', false, {\n\t\"method\": \"DELETE\", // override the default method here\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\n**Note:** If the server doesn't send back JSON, or it cannot be parsed, an error will be thrown.\n\n## XML REST API\n\n```\nPROMISE request.xml( URL, XML )\nPROMISE request.xml( URL, XML, OPTIONS )\n```\n\nThe `xml()` method is designed for sending requests to XML REST APIs.  If you want to send a XML REST style HTTP POST to an API endpoint, and expect to receive a XML formatted response, this wraps up all the serialization and parsing for you.  Example:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.xml( 'http://myserver.com/api', { \n\t\t\"foo\": \"test\", \n\t\t\"bar\": 123 \n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.xml( 'http://myserver.com/api', { \"foo\": \"test\", \"bar\": 123 }, function(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nThis will serialize the object into an XML document (using the [pixl-xml](https://www.github.com/jhuckaby/pixl-xml) package), and send it as the HTTP POST data to the provided URL, with a Content-Type of `text/xml`.  It also expects the response back from the server to be XML, and will parse it for you.  The result will contain the HTTP response object ([IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)), the parsed XML document, and a [performance tracker](#performance-metrics).\n\nYou can also specify options such as custom request headers using this API.  Simply include an options object as the final argument (similar to the `get()` and `post()` methods).  Example:\n\n```js\nlet xml = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\ntry {\n\tlet { resp, data, perf } = await request.xml( 'http://myserver.com/api', xml, {\n\t\t\"headers\": {\n\t\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet xml = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\nrequest.xml( 'http://myserver.com/api', xml, {\n\t\"headers\": {\n\t\t\"X-Custom-Header\": \"My custom value\"\t\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nPlease note that [pixl-xml](https://www.github.com/jhuckaby/pixl-xml) discards the XML root node element when parsing XML, and similarly the request library doesn't expect one when serializing.  Meaning, you should omit the XML root node element (just include the contents), and expect the server XML result to be parsed in a similar fashion.\n\nFor example, if you wanted to send this XML:\n\n```xml\n\u003c?xml version=\"1.0\"?\u003e\n\u003cDocument\u003e\n\t\u003cfoo\u003etest\u003c/foo\u003e\n\t\u003cbar\u003e123\u003c/bar\u003e\n\u003c/Document\u003e\n```\n\nThen just include an object with `foo` and `bar` properties:\n\n```js\n{\n\t\"foo\": \"test\", \n\t\"bar\": 123\n}\n```\n\nSee the [pixl-xml](https://www.github.com/jhuckaby/pixl-xml) documentation for details, including how to include attributes, etc.\n\nBy default, the XML will be serialized to a document with `\u003cRequest\u003e` as the root node name.  However if you are posting to an API that requires a specific XML root node name, you can set it with the `xmlRootNode` property in the options object.  Example of this:\n\n```js\nlet xml = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\ntry {\n\tlet { resp, data, perf } = await request.xml( 'http://myserver.com/api', xml, {\n\t\t\"xmlRootNode\": \"Document\"\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet xml = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\nrequest.xml( 'http://myserver.com/api', xml, {\n\t\"xmlRootNode\": \"Document\"\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nIf you pass `null` or `false` as the XML data argument, the request will be sent as a `GET` instead of a `POST`.  You can also customize the HTTP method by passing a `method` property into the `options` object.  For example, the following would send as a `HTTP PUT` with the XML serialized in the request body:\n\n```js\nlet xml = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\ntry {\n\tlet { resp, data, perf } = await request.xml( 'http://myserver.com/api', xml, {\n\t\t\"method\": \"PUT\", // override the default method here\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nlet xml = {\n\t\"foo\": \"test\", \n\t\"bar\": 123\n};\n\nrequest.xml( 'http://myserver.com/api', xml, {\n\t\"method\": \"PUT\", // override the default method here\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nYou can also send a custom request method with no body:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.xml( 'http://myserver.com/delete/user/234', false, {\n\t\t\"method\": \"DELETE\", // override the default method here\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.xml( 'http://myserver.com/delete/user/234', false, {\n\t\"method\": \"DELETE\", // override the default method here\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\n**Note:** If the server doesn't send back XML, or it cannot be parsed, an error will be thrown.\n\n# Default Headers\n\nBy default the request library will add the following outgoing headers to every request:\n\n```\nUser-Agent: PixlRequest 1.0.0\nAccept-Encoding: gzip, deflate, br\n```\n\nYou can override these by passing in custom headers with your request:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/post', {\n\t\t\"headers\": {\n\t\t\t\"User-Agent\": \"My Request Library!\",\n\t\t\t\"Accept-Encoding\": \"none\"\n\t\t},\n\t\t\"data\": {\n\t\t\t\"full_name\": \"Fred Smith\", \n\t\t\t\"gender\": \"male\",\n\t\t\t\"age\": 35\n\t\t}\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.post( 'http://myserver.com/api/post', {\n\t\"headers\": {\n\t\t\"User-Agent\": \"My Request Library!\",\n\t\t\"Accept-Encoding\": \"none\"\n\t},\n\t\"data\": {\n\t\t\"full_name\": \"Fred Smith\", \n\t\t\"gender\": \"male\",\n\t\t\"age\": 35\n\t}\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nOr by overriding your class instance defaults before making a request:\n\n```js\nrequest.setHeader( \"Accept-Encoding\", \"none\" );\n```\n\nYou can also replace the entire header set by rewriting the `defaultHeaders` property:\n\n```js\nrequest.defaultHeaders = {\n\t\"User-Agent\": \"My Request Library!\",\n\t\"Accept-Encoding\": \"none\"\n};\n```\n\n# Handling Timeouts\n\nPixlRequest handles timeouts in two different ways.  First, by measuring the \"time to first byte\" (TTFB), from the start of the request.  This is *not* an idle timeout, and *not* a connect timeout -- it is the maximum amount of time allowed from the start of the request, to the first byte received.  Separately, it also can track an idle timeout *after* the first byte has been received.  You can set each timeout separately.\n\nThe default TTFB timeout and idle timeout for all requests is 30 seconds.  You can customize this per request by including `timeout` and/or `idleTimeout` properties with your options object, and setting them to a number of milliseconds:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/post', {\n\t\t\"data\": {\n\t\t\t\"full_name\": \"Fred Smith\", \n\t\t\t\"gender\": \"male\",\n\t\t\t\"age\": 35\n\t\t},\n\t\t\"timeout\": 10 * 1000, // 10 second TTFB timeout\n\t\t\"idleTimeout\": 5 * 1000 // 5 second idle timeout\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.post( 'http://myserver.com/api/post', {\n\t\"data\": {\n\t\t\"full_name\": \"Fred Smith\", \n\t\t\"gender\": \"male\",\n\t\t\"age\": 35\n\t},\n\t\"timeout\": 10 * 1000, // 10 second TTFB timeout\n\t\"idleTimeout\": 5 * 1000 // 5 second idle timeout\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nOr you can set default timeouts for all requests on your class instance, using the `setTimeout()` and `setIdleTimeout()` methods:\n\n```js\nrequest.setTimeout( 10 * 1000 ); // 10 seconds\nrequest.setIdleTimeout( 5 * 1000 ); // 5 seconds\n```\n\nWhen a timeout occurs, an `error` event is emitted.  The error message will follow one of these formats, depending on which timeout was fired: \n\n```\nRequest Timeout (### ms)\nIdle Timeout (### ms)\n```\n\nNote that any timeout results in the socket being destroyed (i.e. [request.destroy()](https://nodejs.org/api/http.html#requestdestroyerror) is called on the request object, which in turn destroys the socket).\n\n# Automatic Redirects\n\nThe default behavior for handling redirect responses (i.e. `HTTP 302` and friends) is to *not* follow them automatically, and instead return the original 3xx response.  You can change this by including a `follow` property with your options object, and setting it to the maximum number of redirects you want to allow:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.post( 'http://myserver.com/api/post', {\n\t\t\"data\": {\n\t\t\t\"full_name\": \"Fred Smith\", \n\t\t\t\"gender\": \"male\",\n\t\t\t\"age\": 35\n\t\t},\n\t\t\"follow\": 2, // auto-follow up to 2 redirects\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.post( 'http://myserver.com/api/post', {\n\t\"data\": {\n\t\t\"full_name\": \"Fred Smith\", \n\t\t\"gender\": \"male\",\n\t\t\"age\": 35\n\t},\n\t\"follow\": 2, // auto-follow up to 2 redirects\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \", data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nAlternatively, you can set a class instance default by calling the `setFollow()` method:\n\n```js\nrequest.setFollow( 2 ); // auto-follow up to 2 redirects\n```\n\nIf you want to follow an unlimited number of redirects, set this to boolean `true` (not advised).  To disable the auto-follow behavior, set it to `0` or `false`.\n\nThe library recognizes HTTP codes 301, 302, 307 and 308 as \"redirect\" responses, as long as a `Location` header accompanies them.\n\n# Automatic Errors\n\nWhen using `get()` or `post()`, HTTP response codes like 404 or 500 are *not* considered errors, so you have to look at `resp.statusCode` if you are expecting an HTTP 200.  However, this is configurable.  If you would like all non-200 response codes to be considered errors, call the `setAutoError()` method and pass `true`.  Example:\n\n```js\nrequest.setAutoError( true );\n```\n\nNote that if you allow [redirects](#automatic-redirects), they will not generate an error.\n\nTo customize which response codes are considered \"successful\" and should *not* generate an error, call the `setSuccessMatch()` method, and pass in a new one.  The default match is shown here, which considered any HTTP response code in the 200 - 299 range to be successful:\n\n```js\nrequest.setSuccessMatch( /^2\\d\\d$/ );\n```\n\nNote that this regular expression also affects the [json()](#json-rest-api) and [xml()](#xml-rest-api) wrapper methods.\n\n# Automatic Retries\n\nBy default errors are not retried, and the promise is resolved immediately on the first error.  However, you can enable automatic retries by either including a `retries` property in your options object (set to the maximum number of retries you want to allow), or by calling the `setRetries()` method, and specifying the maximum amount for all requests:\n\n```js\nrequest.setRetries( 5 );\n```\n\nThis example would make up to 6 total attempts (the initial attempt plus up to 5 retries), before ultimately failing the operation and resolving the promise with the last error encountered.\n\nFor the purpose of automatic retries an \"error\" is considered to be any core error emitted on the request object, such as a DNS lookup failure, TCP connect failure, socket timeout, or any HTTP response code in the `5xx` range (500 - 599), such as an `Internal Server Error`.  Any other errors, for example anything in the `4xx` range, are *not* retried, as they are typically considered to be more permanent.\n\n# Compressed Responses\n\nThe request library automatically handles Brotli, Gzip and Deflate encoded responses that come back from the remote server.  These are transparently decoded for you.  However, you should know that by default all outgoing requests include an `Accept-Encoding: gzip, deflate, br` header, which broadcasts our support for it.  If you do not want responses to be compressed, you can unset this header.  See the [Default Headers](#default-headers) section above.\n\nAlternately, if you would prefer that the library not do anything regarding compression, and pass the compressed response directly through without touching it, call the `setAutoDecompress()` method, and pass in `false`:\n\n```js\nrequest.setAutoDecompress( false );\n```\n\n# Abort Signals\n\nIf you have a long-running request that you may want to abort in the middle, you can use a Node.js [AbortController](https://nodejs.org/api/globals.html#class-abortcontroller).  Just pass in the `signal` property from your controller into the request options object, and then you can call `abort()` on the controller whenever you want.  Example:\n\n```js\nconst controller = new AbortController();\n\n// abort after 500ms\nsetTimeout( function() {\n\tcontroller.abort();\n}, 500 );\n\n// send long request\ntry {\n\tlet { resp, data, perf } = await request.get( 'http://myserver.com/some/large/file.mp4', {\n\t\t\"signal\": controller.signal // our abort signal here\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nconst controller = new AbortController();\n\n// abort after 500ms\nsetTimeout( function() {\n\tcontroller.abort();\n}, 500 );\n\n// send long request\nrequest.get( 'http://myserver.com/some/large/file.mp4', {\n\t\"signal\": controller.signal // our abort signal here\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nNote that abort signals are designed to abort requests that have already received the \"first byte\".  Meaning, we already received the response headers, and are streaming down the data.  That's the phase of the request that is \"abortable\".\n\n# Performance Metrics\n\nThe request library keeps high resolution performance metrics on every HTTP request, including the DNS lookup time, socket connect time, request send time, wait time, receive time, decompress time, and total elapsed time.  These are all tracked using the [pixl-perf](https://www.github.com/jhuckaby/pixl-perf) module, and included in the result object for all operations.  Example use:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.get( 'https://www.bitstamp.net/api/ticker/' );\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.get( 'https://www.bitstamp.net/api/ticker/', function(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nThis would output something like the following:\n\n```\nStatus: 200 OK\nPerformance: { \n  scale: 1000,\n  perf: { \n     total: 548.556,\n     dns: 25.451,\n     connect: 120.155,\n     send: 270.92,\n     wait: 122.2,\n     receive: 3.462,\n     decompress: 4.321 \n  },\n  counters: { \n    bytes_sent: 134, \n    bytes_received: 749 \n  } \n}\n```\n\nAll the `perf` values are in milliseconds (represented by the `scale`).  Here are descriptions of all the metrics:\n\n| Metric | Description |\n|--------|-------------|\n| `dns` | Time to resolve the hostname to an IP address via DNS.  Omitted if cached, or you specify an IP on the URL. |\n| `connect` | Time to connect to the remote socket (omitted if using Keep-Alives and reusing a host). |\n| `send` | Time to send the request data (typically for POST / PUT).  Also includes SSL handshake time (if HTTPS). |\n| `wait` | Time spent waiting for the server response (after request is sent). |\n| `receive` | Time spent downloading data from the server (after headers received). |\n| `decompress` | Time taken to decompress the response (if encoded with Brotli, Gzip or Deflate). |\n| `total` | Total time of the entire HTTP transaction. |\n\nAs indicated above, some of the properties may be omitted depending on the situation.  For example, if you are using a shared [http.Agent](https://nodejs.org/api/http.html#class-httpagent) with Keep-Alives, then subsequent requests to the same host won't perform a DNS lookup or socket connect, so those two metrics will be omitted.  Similarly, if the response from the server isn't compressed, then the `decompress` metric will be omitted.\n\nNote that the `send` metric includes the SSL / TLS handshake time, if using HTTPS.  Also, this metric may be `0` if using plain HTTP GET or HEAD, as it is mainly used to measure the POST or PUT data send time (i.e. uploading file data).\n\nThe `bytes_sent` and `bytes_received` values in the `counters` object represent the total amount of raw bytes sent and received over the socket.  This includes the raw request line and request/response headers.\n\nSee the [pixl-perf](https://www.github.com/jhuckaby/pixl-perf) module for more details.\n\n# DNS Caching\n\nYou can optionally have the library cache DNS lookups in RAM, for faster subsequent requests on the same hostnames.  You can also specify the TTL (time to live) to control how long hostnames will be cached.  This means it will only request a DNS lookup for a given hostname once every N seconds.  To enable this feature, call `setDNSCache()` and specify the number of seconds for the TTL:\n\n```js\nrequest.setDNSCache( 300 ); // 5 minute TTL\n```\n\nThis will cache hostnames and their IP addresses in RAM for 5 minutes.  Meaning, during that time subsequent requests to the same hostname will not require a DNS lookup.  After 5 minutes, the cache objects will expire, and the next request will perform another DNS lookup.\n\nNote that while the feature can be enabled or disabled per request object, the DNS cache itself is global.  Meaning, it is shared by all `pixl-request` objects in the same process.\n\n## Flushing the Cache\n\nTo flush the DNS cache (i.e. eject all the IPs from it), call the `flushDNSCache()` method.  Example:\n\n```js\nrequest.flushDNSCache();\n```\n\n# SSL Certificate Validation\n\nIf you are trying to connect to a host via HTTPS and getting certificate errors, you may have to bypass Node's SSL certification validation.  To do this, set the `rejectUnauthorized` options property to `false`.  Example:\n\n```js\ntry {\n\tlet { resp, data, perf } = await request.get( 'https://www.bitstamp.net/api/ticker/', {\n\t\t\"rejectUnauthorized\": false\n\t});\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n}\ncatch (err) {\n\tthrow err;\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eExample using callback\u003c/strong\u003e\u003c/summary\u003e\n\n```js\nrequest.get( 'https://www.bitstamp.net/api/ticker/', {\n\t\"rejectUnauthorized\": false\n}, \nfunction(err, resp, data, perf) {\n\tif (err) throw err;\n\tconsole.log(\"Status: \" + resp.statusCode + ' ' + resp.statusMessage);\n\tconsole.log(\"Headers: \", resp.headers);\n\tconsole.log(\"Content: \" + data);\n\tconsole.log(\"Performance: \", perf.metrics());\n} );\n```\n\n\u003c/details\u003e\n\nPlease only do this if you understand the security ramifications, and *completely trust* the host you are connecting to, and the network you are on.  Skipping the certificate validation step should really only be done in special circumstances, such as testing your own internal server with a self-signed cert.\n\n# Proxy Servers\n\nTo send requests through a proxy, simply set one or more of the [de-facto standard environment variables](https://curl.se/docs/manpage.html#ENVIRONMENT) used for this purpose:\n\n```\nHTTPS_PROXY\nHTTP_PROXY\nALL_PROXY\nNO_PROXY\n```\n\nThe pixl-request library will detect these environment variables and automatically configure proxy routing for your requests.  The environment variable names may be upper or lower-case.  The proxy format should be a fully-qualified URL with port number.  To set a single proxy server for handling both HTTP and HTTPS requests, the simplest way is to just set `ALL_PROXY` (usually specified via a plain HTTP URL with port).  Example:\n\n```\nALL_PROXY=http://company-proxy-server.com:8080\n```\n\nUse the `NO_PROXY` environment variable to specify a comma-separated domain whitelist.  Requests to any of the domains on this list will bypass the proxy and be sent directly.  Example:\n\n```\nNO_PROXY=direct.example.com\n```\n\nPlease note that for proxying HTTPS (SSL) requests, unless you have pre-configured your client machine to trust your proxy's local SSL cert, you will have to set the `rejectUnauthorized` option to `false` in your requests.  See [SSL Certificate Validation](#ssl-certificate-validation) above for details.\n\nThe types of proxies supported are:\n\n| Protocol | Example |\n|----------|---------|\n| `http` | `http://proxy-server-over-tcp.com:3128` |\n| `https` | `https://proxy-server-over-tls.com:3129` |\n| `socks` | `socks://username:password@some-socks-proxy.com:9050` |\n| `socks5` | `socks5://username:password@some-socks-proxy.com:9050` |\n| `socks4` | `socks4://some-socks-proxy.com:9050` |\n| `pac-*` | `pac+http://www.example.com/proxy.pac` |\n\n# License\n\n**The MIT License**\n\n*Copyright (c) 2015 - 2025 Joseph Huckaby.*\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhuckaby%2Fpixl-request","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjhuckaby%2Fpixl-request","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhuckaby%2Fpixl-request/lists"}