From c080439382f1619fc664fcdb81788e4466d94b0e Mon Sep 17 00:00:00 2001 From: Vsevolod Strukchinsky Date: Thu, 4 Dec 2014 20:51:17 +0500 Subject: [PATCH] Implement got as WritableStream on POST and PUT Closes #16 * Add shortcuts for POST and PUT methods * Throw error on write attempt with options.body --- index.js | 44 +++++++++++++++++++++++++++++++++++--------- package.json | 1 + readme.md | 13 +++++++++++++ test.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index ff10c37..e9c742a 100644 --- a/index.js +++ b/index.js @@ -3,12 +3,12 @@ var http = require('http'); var https = require('https'); var urlLib = require('url'); var zlib = require('zlib'); -var PassThrough = require('stream').PassThrough; +var duplexify = require('duplexify'); var assign = require('object-assign'); var read = require('read-all-stream'); var timeout = require('timed-out'); -module.exports = function (url, opts, cb) { +function got (url, opts, cb) { if (typeof opts === 'function') { // if `cb` has been specified but `opts` has not cb = opts; @@ -25,15 +25,15 @@ module.exports = function (url, opts, cb) { var body = opts.body; delete opts.body; - if (body && opts.method === undefined) { - opts.method = 'POST'; + if (body) { + opts.method = opts.method || 'POST'; } // returns a proxy stream to the response // if no callback has been provided var proxy; if (!cb) { - proxy = new PassThrough(); + proxy = duplexify(); // forward errors on the stream cb = function (err) { @@ -86,7 +86,7 @@ module.exports = function (url, opts, cb) { // pipe the response to the proxy if in proxy mode if (proxy) { - res.on('error', proxy.emit.bind(proxy, 'error')).pipe(proxy); + proxy.setReadable(res); return; } @@ -97,16 +97,42 @@ module.exports = function (url, opts, cb) { timeout(req, opts.timeout); } - if (!body) { - req.end(); + if (!proxy) { + req.end(body); + return; + } + + if (body) { + proxy.write = function () { + throw new Error('got\'s stream is not writable when options.body is used'); + }; + req.end(body); + return; + } + + if (opts.method === 'POST' || opts.method === 'PUT') { + proxy.setWritable(req); return; } - req.write(body); req.end(); }; get(url, opts, cb); return proxy; +} + +got.post = function (url, opts, cb) { + opts = opts || {}; + opts.method = 'POST'; + return got(url, opts, cb); }; + +got.put = function (url, opts, cb) { + opts = opts || {}; + opts.method = 'PUT'; + return got(url, opts, cb); +}; + +module.exports = got; diff --git a/package.json b/package.json index a318616..dad94ae 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "simple" ], "dependencies": { + "duplexify": "^3.2.0", "object-assign": "^2.0.0", "read-all-stream": "^0.1.0", "timed-out": "^2.0.0" diff --git a/readme.md b/readme.md index c5b1f89..96d8f7b 100644 --- a/readme.md +++ b/readme.md @@ -27,8 +27,12 @@ got('http://todomvc.com', function (err, data, res) { //=> ... }); + // Stream mode. got('http://todomvc.com').pipe(fs.createWriteStream('index.html')); + +// For POST and PUT methods got returns WritableStream +fs.createReadStream('index.html').pipe(got.post('http://todomvc.com')); ``` ### API @@ -63,6 +67,8 @@ Type: `string`, `Buffer` Body, that will be sent with `POST` request. If present in `options` and `options.method` is not set - `options.method` will be set to `POST`. +This option and stream mode are mutually exclusive. + ##### options.timeout Type: `number` @@ -83,6 +89,13 @@ The data you requested. The [response object](http://nodejs.org/api/http.html#http_http_incomingmessage). +#### got.post(url, [options], [callback]) + +Sets options.method to POST and makes a request. + +#### got.put(url, [options], [callback]) + +Sets options.method to PUT and makes a request. ## Related diff --git a/test.js b/test.js index 99d6ff6..b2f9697 100644 --- a/test.js +++ b/test.js @@ -133,4 +133,47 @@ describe('with POST ', function () { done(); }); }); + + it('should take data from options.body in stream mode', function (done) { + got.post('http://0.0.0.0:8081', { body: 'Hello' }) + .on('error', done) + .on('data', function (chunk) { + assert.equal(chunk, 'Hello'); + done(); + }); + }); + + it('should throw an error on options.body and write operations', function (done) { + assert.throws(function () { + got.post('http://0.0.0.0:8081', { body: 'Hello' }) + .end('Hello'); + }, 'got\'s stream is not writable when options.body is used'); + + assert.throws(function () { + got.post('http://0.0.0.0:8081', { body: 'Hello' }) + .write('Hello'); + }, 'got\'s stream is not writable when options.body is used'); + + done(); + }); + + it('should be a writeable stream on POST', function (done) { + got.post('http://0.0.0.0:8081') + .on('error', done) + .on('data', function (chunk) { + assert.equal(chunk, 'Hello'); + done(); + }) + .end('Hello'); + }); + + it('should be a writeable stream on PUT', function (done) { + got.put('http://0.0.0.0:8081') + .on('error', done) + .on('data', function (chunk) { + assert.equal(chunk, 'Hello'); + done(); + }) + .end('Hello'); + }); });