Skip to content

Commit

Permalink
working multipart/form-data posts and now bundles whole module
Browse files Browse the repository at this point in the history
  • Loading branch information
brianleroux committed Jan 18, 2018
1 parent 5b2704f commit 17979de
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 28 deletions.
1 change: 0 additions & 1 deletion .gitignore
@@ -1,2 +1 @@
node_modules/
bundle.js
11 changes: 6 additions & 5 deletions .npmignore
@@ -1,5 +1,6 @@
.gitignore
bundle.js
test-get.js
test-post.js
test-promise.js
.*
test-*.js
index.js
_read.js
_write.js
node_modules
63 changes: 49 additions & 14 deletions _write.js
@@ -1,6 +1,7 @@
var qs = require('querystring')
var http = require('http')
var https = require('https')
var FormData = require('@brianleroux/form-data')
var url = require('url')

module.exports = function _write(httpMethod, options, callback) {
Expand All @@ -25,40 +26,73 @@ module.exports = function _write(httpMethod, options, callback) {
var method = opts.protocol === 'https:'? https.request : http.request
var defaultContentType = 'application/json; charset=utf-8'

// put the params on the query as well as the body?
// put the params on the query
if (httpMethod === 'DELETE' && options.data) {
var isSearch = !!opts.search
options.url += (isSearch? '&' : '?') + qs.stringify(options.data)
opts = url.parse(options.url)
}

// wrangle defaults
opts.method = httpMethod
opts.rejectUnauthorized = false
opts.headers = options.headers || {}
opts.headers['User-Agent'] = opts.headers['User-Agent'] || 'tiny-http'
opts.headers['Content-Type'] = opts.headers['Content-Type'] || defaultContentType
var reqJSON = opts.headers['Content-Type'].startsWith('application/json')
var postData = reqJSON? JSON.stringify(options.data || {}) : qs.stringify(options.data || {})

// default to regular POST body (url enc)
var postData = qs.stringify(options.data || {})
var contentTypeEquals = c=> opts.headers['Content-Type'] && opts.headers['Content-Type'].startsWith(c)

function is(headers, type) {
var isU = headers['Content-Type'] && headers['Content-Type'].startsWith(type)
var isL = headers['content-type'] && headers['content-type'].startsWith(type)
return isU || isL
}

// if we're posting JSON stringify options.data
var isJSON = is(opts.headers, 'application/json')
if (isJSON) {
postData = JSON.stringify(options.data || {})
}

// ensure we know the len ~after~ we set the postData
opts.headers['Content-Length'] = postData.length

// if we're doing a mutipart/form-data do that encoding
// we'll overload `method` and use the custom form-data submit instead of http.request
var isMultipart = contentTypeEquals('multipart/form-data')
if (isMultipart) {
method = function _multiPartFormDataPost(params, streamback) {
var form = new FormData
Object.keys(options.data).forEach(k=> {
form.append(k, options.data[k])
})
form.submit(opts, function _submit(err, res) {
if (err) callback(err)
else streamback(res)
})
}
}

// make a POST request
// make a request
var req = method(opts, function(res) {
var raw = [] // keep our buffers here
var ok = res.statusCode >= 200 && res.statusCode < 300

res.on('data', function __data(chunk) {
res.on('data', function _data(chunk) {
raw.push(chunk)
})

res.on('end', function __end() {
res.on('end', function _end() {
var err = null
var result = null

try {
var isJSON = res.headers['content-type'].startsWith('application/json')
result = Buffer.concat(raw)

if (!options.buffer) {
var isJSON = is(res.headers, 'application/json')
result = isJSON ? JSON.parse(result.toString()) : result.toString()
}
}
Expand All @@ -71,17 +105,18 @@ module.exports = function _write(httpMethod, options, callback) {
err.raw = res
err.body = result
callback(err)
} else {
}
else {
callback(err, {body:result, headers:res.headers})
}
})
})

req.on('error', callback)

req.write(postData)

req.end()
if (!isMultipart) {
req.on('error', callback)
req.write(postData)
req.end()
}

return promise
}
1 change: 1 addition & 0 deletions bundle.js

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions package.json
@@ -1,10 +1,10 @@
{
"name": "tiny-json-http",
"version": "5.3.2",
"main": "index.js",
"main": "bundle.js",
"scripts": {
"test": "tape test-* | tap-spec",
"build": "browserify index --standalone tiny | uglifyjs -c > bundle.js"
"build": "browserify index --node --standalone tiny | uglifyjs -c > bundle.js"
},
"repository": {
"type": "git",
Expand All @@ -13,12 +13,13 @@
"author": "Brian LeRoux <b@brian.io>",
"license": "Apache-2.0",
"devDependencies": {
"@brianleroux/form-data": "^1.0.3",
"body-parser": "^1.17.1",
"browserify": "^14.1.0",
"express": "^4.15.2",
"tap-spec": "^4.1.1",
"tape": "^4.6.2",
"uglifyify": "^3.0.4",
"uglifyjs": "^2.4.10"
}
"uglify-es": "^3.3.7"
},
"dependencies": {}
}
6 changes: 3 additions & 3 deletions readme.md
Expand Up @@ -2,7 +2,7 @@

Minimalist `HTTP` client for `GET` and `POST`ing `JSON` payloads

- Zero dependencies: perfect for AWS Lambda or Browserify
- Zero dependencies: perfect for AWS Lambda
- Sensible default: assumes buffered JSON responses
- System symmetry: Node style errback API, or Promises for use with Async/Await

Expand All @@ -23,7 +23,7 @@ _*callback is optional, tiny methods will return a promise if no callback is pro

- `url` *required*
- `data` form vars for `tiny.post`, `tiny.put`, and `tiny.delete` otherwise querystring vars for `tiny.get`
- `headers` key/value map used for headers
- `headers` key/value map used for headers (including support for uploading files with `mulitpart/form-data`)
- `buffer` if set to `true` the response body is returned as a buffer

### callback values
Expand All @@ -36,7 +36,7 @@ _*callback is optional, tiny methods will return a promise if no callback is pro
- if no `callback` is provided to the tiny-json-http methods, a promise is returned
- perfect for use of async/await

## example
## examples

#### With Async / Await

Expand Down
58 changes: 58 additions & 0 deletions test-qq-multipart.js
@@ -0,0 +1,58 @@
var test = require('tape')
var fs = require('fs')
var tiny = require('.')
var http = require('http')
var server

test('make a multipart post', t=> {
t.plan(1)
t.ok(tiny, 'got env')
})

test('start a fake server', t=> {
t.plan(1)
// somebody thought this was intuitive
server = http.createServer((req, res)=> {
var body = []
req.on('data', function _data(data) {
//console.log(data.toString())
body.push(data)
})
req.on('end', function _end() {
console.log('END', Buffer.concat(body).toString())
})
res.end('ugh')
}).listen(3333, x=> {
t.ok(true, 'opened server')
})
})

test('can multipart/form-data post', t=> {
t.plan(1)
tiny.post({
url: 'http://localhost:3333',
headers: {
'Content-Type': 'multipart/form-data'
},
data: {
one: 1,
anotherFile: fs.createReadStream(__dirname + '/readme.md')
}
},
function _post(err, data) {
if (err) {
t.fail(err, err)
console.log(err)
}
else {
t.ok(true, 'posted')
console.log(data)
}
})
})

test('close fake server', t=> {
t.plan(1)
server.close()
t.ok(true, 'server closed')
})

0 comments on commit 17979de

Please sign in to comment.