├── .gitignore ├── README.md ├── lib └── network.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Tiny module for http requests with no dependencies 2 | 3 | ## Install 4 | npm install tiny_request 5 | 6 | ## Simple to use 7 | 8 | 9 | ```js 10 | var req = require('tiny_request') 11 | 12 | req.get('http://google.com', function(body, response, err){ 13 | if (!err && response.statusCode == 200) { 14 | console.log(body) 15 | } 16 | }) 17 | ``` 18 | ## Examples 19 | 20 | - [JSON](#json) 21 | - [GET](#get) 22 | - [POST Multipart](#post-multipart) 23 | - [POST Froms](#post-forms) 24 | - [Custom HTTP Headers](#custom-http-headers) 25 | - [Stream](#stream) 26 | - [Timeout](#timeout) 27 | 28 | ## JSON 29 | 30 | To automatically parse JSON you just need to pass JSON parameter. 31 | 32 | Example: 33 | 34 | ```js 35 | req.get({ url: 'http://test.com/json', json: true}, function(body, response, err){ 36 | if (!err && response.statusCode == 200) { 37 | console.log(body) //body now is parsed JSON object 38 | } 39 | }) 40 | ``` 41 | 42 | ## GET 43 | 44 | ```js 45 | req.get({ url: 'http://test.com', query: { test: 'test' }}, function(body, response, err){ 46 | if (!err && response.statusCode == 200) { 47 | console.log(body) 48 | } 49 | }) 50 | ``` 51 | Where query is GET parameters object 52 | 53 | Also you can pass port parameter, for example: 54 | 55 | ```js 56 | req.get({ url: 'http://test.com', port: 8080}, function(body, response, err){ 57 | if (!err && response.statusCode == 200) { 58 | console.log(body) 59 | } 60 | }) 61 | ``` 62 | 63 | ## POST Multipart 64 | 65 | ```js 66 | var data = { 67 | image: { 68 | value: fs.createReadStream('photo.png'), 69 | filename: 'photo.png', 70 | contentType: 'image/png' 71 | }, 72 | test: 'test' 73 | } 74 | 75 | req.post({ 76 | url: 'http://test.com', 77 | query: { test: 'test' }, 78 | multipart: data 79 | }, function(body, response, err){ 80 | if (!err && response.statusCode == 200) { 81 | console.log(body) 82 | } 83 | }) 84 | ``` 85 | 86 | ## POST Forms 87 | 88 | ```js 89 | var form = { 90 | test: 'test' 91 | } 92 | 93 | req.post({ url: 'http://test.com', form: form}, function(body, response, err){ 94 | if (!err && response.statusCode == 200) { 95 | console.log(body) 96 | } 97 | }) 98 | ``` 99 | 100 | ## POST Json 101 | 102 | ```js 103 | var data = { 104 | test: 'test' 105 | } 106 | 107 | req.post({ url: 'http://test.com', jsonData: data}, function(body, response, err){ 108 | if (!err && response.statusCode == 200) { 109 | console.log(body) 110 | } 111 | }) 112 | ``` 113 | 114 | ## Custom HTTP Headers 115 | 116 | ```js 117 | var headers = { 118 | 'Test-Header': 'test' 119 | } 120 | 121 | req.post({ url: 'http://test.com', headers: headers}, function(body, response, err){ 122 | if (!err && response.statusCode == 200) { 123 | console.log(body) 124 | } 125 | }) 126 | ``` 127 | 128 | ## Stream 129 | 130 | ```js 131 | req.get({url: url, pipe: stream}) 132 | ``` 133 | 134 | ## Timeout 135 | 136 | ```js 137 | req.get({url: url, timeout: 1000}) 138 | 139 | Request will be aborted after 1 second if there is no response from server 140 | ``` 141 | -------------------------------------------------------------------------------- /lib/network.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fs = require('fs') 4 | const url = require('url') 5 | const http = require('http') 6 | const https = require('https') 7 | 8 | class Network { 9 | constructor() { 10 | this._protocols = { 11 | http, 12 | https 13 | } 14 | } 15 | 16 | _request(options, callback) { 17 | var self = this 18 | 19 | callback = callback || Function() 20 | 21 | var _url = url.parse(options.url ? options.url : options) 22 | var protocol = _url.protocol.substr(0, _url.protocol.length - 1) 23 | var port 24 | 25 | if (_url.protocol === 'http:') 26 | port = 80 27 | if (_url.protocol === 'https:') 28 | port = 443 29 | 30 | if (options.port) { 31 | port = options.port 32 | } 33 | if (_url.host === null) { 34 | callback(undefined, undefined, new Error()) 35 | return 36 | } 37 | if (typeof options === 'string') { 38 | var req_options = { 39 | host: _url.host, 40 | path: _url.pathname, 41 | port: port, 42 | method: options.method 43 | } 44 | } else { 45 | var queryStr = _url.query ? (_url.query + '&') : '' 46 | if (options.query !== undefined) { 47 | queryStr += self._renderUrlencoded(options.query) 48 | } 49 | req_options = { 50 | host: _url.host, 51 | path: _url.pathname + (queryStr ? '?' + queryStr : ''), 52 | port: port, 53 | method: options.method, 54 | headers: options.headers, 55 | timeout: options.timeout 56 | } 57 | } 58 | var req = this._protocols[protocol].request(req_options, (response) => { 59 | if (options.pipe !== undefined) { 60 | response.pipe(options.pipe) 61 | } 62 | 63 | var chunks = [] 64 | response.on('data', (chunk) => { 65 | chunks.push(chunk) 66 | }) 67 | response.on('end', () => { 68 | var data = Buffer.concat(chunks).toString('utf-8') 69 | if (options.json !== undefined && options.json == true) { 70 | try { 71 | var obj = JSON.parse(data) 72 | } catch (e) { 73 | callback(data, undefined, e) 74 | return 75 | } 76 | callback(obj, response) 77 | return 78 | } else { 79 | callback(data, response) 80 | } 81 | }) 82 | 83 | }) 84 | 85 | if (options.timeout) { 86 | req.setTimeout(options.timeout, (e) => { 87 | req.abort() 88 | }) 89 | } 90 | 91 | if (req_options.method === 'POST' && options.multipart) { 92 | var data = options.multipart 93 | var names = Object.keys(options.multipart) 94 | var boundaryKey = Math.random().toString(16) 95 | var body = this._renderMultipartBody(names, data, boundaryKey) 96 | var length = 0 97 | 98 | req.setHeader('Content-Type', 'multipart/form-data; boundary="' + boundaryKey + '"') 99 | 100 | body.forEach((part) => { 101 | length = length + Buffer.byteLength(part) 102 | }) 103 | names.forEach((name) => { 104 | if (data[name].value !== undefined) { 105 | length = length + self._getFilesizeInBytes(data[name].value.path) 106 | } 107 | }) 108 | req.setHeader('Content-Length', length + (16 * (names.length - 1)) + 8 + Buffer.byteLength(boundaryKey)) 109 | 110 | this._sendMultipartParts(boundaryKey, body, data, names, req, 0) 111 | } else if (req_options.method == 'POST' && options.jsonData) { 112 | req.setHeader('Content-Type', 'application/json') 113 | var body = JSON.stringify(options.jsonData) 114 | req.setHeader('Content-Length', Buffer.byteLength(body)) 115 | req.end(body) 116 | } else { 117 | if (req_options.method == 'POST' && options.form) { 118 | req.setHeader('Content-Type', 'application/x-www-form-urlencoded') 119 | var body = self._renderUrlencoded(options.form) 120 | req.setHeader('Content-Length', Buffer.byteLength(body)) 121 | req.end(body) 122 | } else { 123 | req.setHeader('Content-Length', 0) 124 | req.end() 125 | } 126 | } 127 | req.on('error', (e) => { 128 | callback(undefined, undefined, e) 129 | }) 130 | } 131 | 132 | _renderMultipartBody(names, data, boundaryKey) { 133 | var body = [] 134 | names.forEach((name, i) => { 135 | if (data[name].value !== undefined) { 136 | body[i] = '--' + boundaryKey + '\r\n' + 137 | 'Content-Type: ' + data[name].contentType + '\r\n' + 138 | 'Content-Disposition: form-data; name="' + name + '"; filename="' + data[name].filename + '"\r\n' + 139 | 'Content-Transfer-Encoding: binary\r\n\r\n' 140 | } else { 141 | body[i] = '--' + boundaryKey + '\r\n' + 'Content-Disposition: form-data; name="' + name + '"\r\n\r\n' + data[name] 142 | } 143 | }) 144 | return body 145 | } 146 | 147 | _sendMultipartParts(boundaryKey, body, data, names, req, i) { 148 | var self = this 149 | 150 | req.write('\r\n' + body[i]) 151 | 152 | if (data[names[i]].value !== undefined) { 153 | data[names[i]].value 154 | .on('end', () => { 155 | if (i + 1 <= names.length - 1) { 156 | req.write('\r\n--' + boundaryKey) 157 | self._sendMultipartParts(boundaryKey, body, data, names, req, i + 1) 158 | } else { 159 | req.end('\r\n--' + boundaryKey + '--') 160 | } 161 | }) 162 | .pipe(req, { 163 | end: false 164 | }) 165 | } else { 166 | if (i + 1 <= names.length - 1) { 167 | req.write('\r\n--' + boundaryKey) 168 | self._sendMultipartParts(boundaryKey, body, data, names, req, i + 1) 169 | } else { 170 | req.end('\r\n--' + boundaryKey + '--') 171 | } 172 | } 173 | } 174 | 175 | _getFilesizeInBytes(filename) { 176 | return fs.statSync(filename).size 177 | } 178 | 179 | /** 180 | * @param {object} query 181 | * @returns {string} 182 | * @private 183 | */ 184 | _renderUrlencoded(query) { 185 | let queryStr = '' 186 | for (const key in query) { 187 | if (queryStr != '') 188 | queryStr += '&' 189 | 190 | queryStr += key + '=' + encodeURIComponent(query[key]) 191 | } 192 | 193 | return queryStr 194 | } 195 | 196 | get(options, callback) { 197 | if (typeof options === 'string') { 198 | this._request({ url: options, method: 'GET' }, callback) 199 | return 200 | } 201 | 202 | options.method = 'GET' 203 | this._request(options, callback) 204 | } 205 | 206 | post(options, callback) { 207 | if (typeof options === 'string') { 208 | this._request({ url: options, method: 'POST' }, callback) 209 | return 210 | } 211 | 212 | options.method = 'POST' 213 | this._request(options, callback) 214 | } 215 | 216 | put(options, callback) { 217 | if (typeof options === 'string') { 218 | this._request({ url: options, method: 'PUT' }, callback) 219 | return 220 | } 221 | 222 | options.method = 'PUT' 223 | this._request(options, callback) 224 | } 225 | } 226 | 227 | module.exports = new Network() 228 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiny_request", 3 | "version": "1.0.13", 4 | "description": "Tiny module for networking", 5 | "main": "lib/network.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/Naltox/tiny_request.git" 12 | }, 13 | "keywords": [ 14 | "network", 15 | "tiny", 16 | "request" 17 | ], 18 | "author": "Narek Abovyan ", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/Naltox/tiny_request/issues" 22 | }, 23 | "homepage": "https://github.com/Naltox/tiny_request" 24 | } 25 | --------------------------------------------------------------------------------