diff --git a/index.js b/index.js index 7f59de523..978572e95 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,7 @@ var PinkiePromise = require('pinkie-promise'); var unzipResponse = require('unzip-response'); var createErrorClass = require('create-error-class'); var nodeStatusCodes = require('node-status-codes'); +var isPlainObj = require('is-plain-obj'); function requestAsEventEmitter(opts) { opts = opts || {}; @@ -198,12 +199,17 @@ function normalizeArguments(url, opts) { var body = opts.body; if (body) { - if (typeof body !== 'string' && !Buffer.isBuffer(body) && !isStream.readable(body)) { - throw new Error('options.body must be a ReadableStream, string or Buffer'); + if (typeof body !== 'string' && !Buffer.isBuffer(body) && !isStream.readable(body) && !isPlainObj(body)) { + throw new Error('options.body must be a ReadableStream, string, Buffer or plain Object'); } opts.method = opts.method || 'POST'; + if (isPlainObj(body)) { + opts.headers['content-type'] = 'application/x-www-form-urlencoded'; + body = opts.body = querystring.stringify(body); + } + if (!opts.headers['content-length'] && !opts.headers['transfer-encoding'] && !isStream.readable(body)) { var length = typeof body === 'string' ? Buffer.byteLength(body) : body.length; opts.headers['content-length'] = length; diff --git a/package.json b/package.json index 65b15f3bc..1d005483a 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "dependencies": { "create-error-class": "^2.0.0", "duplexify": "^3.2.0", + "is-plain-obj": "^1.0.0", "is-redirect": "^1.0.0", "is-stream": "^1.0.0", "lowercase-keys": "^1.0.0", diff --git a/readme.md b/readme.md index cabaea82c..ebb6eed38 100644 --- a/readme.md +++ b/readme.md @@ -72,7 +72,7 @@ Any of the [`http.request`](http://nodejs.org/api/http.html#http_http_request_op ###### body -Type: `string`, `Buffer`, `ReadableStream` +Type: `string`, `Buffer`, `ReadableStream`, `Object` *This is mutually exclusive with stream mode.* @@ -82,6 +82,8 @@ If present in `options` and `options.method` is not set, `options.method` will b If `content-length` or `transfer-encoding` is not set in `options.headers` and `body` is a string or buffer, `content-length` will be set to the body length. +If `body` is a plain Object, it will be stringified and sent as `application/x-www-form-urlencoded`. + ###### encoding Type: `string`, `null` diff --git a/test/test-error.js b/test/test-error.js index da05a14c7..5e8a67290 100644 --- a/test/test-error.js +++ b/test/test-error.js @@ -37,8 +37,8 @@ test('dns error message', function (t) { test('options.body error message', function (t) { t.throws(function () { - got(s.url, {body: {}}); - }, /options.body must be a ReadableStream, string or Buffer/); + got(s.url, {body: function () {}}); + }, /options.body must be a ReadableStream, string, Buffer or plain Object/); t.end(); }); diff --git a/test/test-post.js b/test/test-post.js index 540bb5b3d..8e2c61de4 100644 --- a/test/test-post.js +++ b/test/test-post.js @@ -100,6 +100,14 @@ test('post have content-length header to string', function (t) { }); }); +test('works with plain object in body', function (t) { + got(s.url, {body: {such: 'wow'}}, function (err, data) { + t.error(err); + t.equal(data, 'such=wow'); + t.end(); + }); +}); + test('cleanup', function (t) { s.close(); t.end();