Skip to content

Commit f3b97db

Browse files
committed
feat(body): automatic handling of different opts.body values
1 parent 84b94ba commit f3b97db

File tree

2 files changed

+118
-5
lines changed

2 files changed

+118
-5
lines changed

index.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,26 @@ function regFetch (uri, opts) {
4040
// through that takes into account the scope, the prefix of `uri`, etc
4141
const startTime = Date.now()
4242
const conf = opts.config
43+
const headers = getHeaders(registry, uri, opts)
44+
let body = opts.body
45+
const bodyIsStream = body &&
46+
typeof body === 'object' &&
47+
typeof body.pipe === 'function'
48+
if (body && !bodyIsStream && typeof body !== 'string' && !Buffer.isBuffer(body)) {
49+
headers['content-type'] = headers['content-type'] || 'application/json'
50+
body = JSON.stringify(body)
51+
} else if (body && !headers['content-type']) {
52+
headers['content-type'] = 'application/octet-stream'
53+
}
4354
return fetch(uri, {
4455
agent: opts.agent,
4556
algorithms: opts.algorithms,
57+
body,
4658
cache: getCacheMode(conf),
4759
cacheManager: conf.get('cache'),
4860
ca: conf.get('ca'),
4961
cert: conf.get('cert'),
50-
headers: getHeaders(registry, uri, opts),
62+
headers,
5163
integrity: opts.integrity,
5264
key: conf.get('key'),
5365
localAddress: conf.get('local-address'),

test/index.js

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
'use strict'
22

3+
const Buffer = require('safe-buffer').Buffer
4+
35
const npmlog = require('npmlog')
6+
const PassThrough = require('stream').PassThrough
47
const test = require('tap').test
58
const tnock = require('./util/tnock.js')
69

@@ -34,17 +37,115 @@ test('hello world', t => {
3437
.get('/hello')
3538
.reply(200, {hello: 'world'})
3639
return fetch('/hello', OPTS)
40+
.then(res => {
41+
t.equal(res.status, 200, 'got successful response')
42+
return res.json()
43+
})
44+
.then(json => t.deepEqual(json, {hello: 'world'}, 'got correct body'))
45+
})
46+
47+
test('JSON body param', t => {
48+
tnock(t, OPTS.config.get('registry'))
49+
.matchHeader('content-type', ctype => {
50+
t.equal(ctype[0], 'application/json', 'content-type automatically set')
51+
return ctype[0] === 'application/json'
52+
})
53+
.post('/hello')
54+
.reply(200, (uri, reqBody) => {
55+
t.deepEqual(reqBody, {
56+
hello: 'world'
57+
}, 'got the JSON version of the body')
58+
return reqBody
59+
})
60+
const opts = Object.assign({
61+
method: 'POST',
62+
body: {hello: 'world'}
63+
}, OPTS)
64+
return fetch('/hello', opts)
3765
.then(res => {
3866
t.equal(res.status, 200)
3967
return res.json()
4068
})
4169
.then(json => t.deepEqual(json, {hello: 'world'}))
4270
})
4371

44-
test('json()')
45-
test('method configurable')
46-
test('npm-notice header logging')
47-
test('optionally verifies request body integrity')
72+
test('buffer body param', t => {
73+
tnock(t, OPTS.config.get('registry'))
74+
.matchHeader('content-type', ctype => {
75+
t.equal(ctype[0], 'application/octet-stream', 'content-type automatically set')
76+
return ctype[0] === 'application/octet-stream'
77+
})
78+
.post('/hello')
79+
.reply(200, (uri, reqBody) => {
80+
t.deepEqual(
81+
Buffer.from(reqBody, 'utf8'),
82+
Buffer.from('hello', 'utf8'),
83+
'got the JSON version of the body'
84+
)
85+
return reqBody
86+
})
87+
const opts = Object.assign({
88+
method: 'POST',
89+
body: Buffer.from('hello', 'utf8')
90+
}, OPTS)
91+
return fetch('/hello', opts)
92+
.then(res => {
93+
t.equal(res.status, 200)
94+
return res.buffer()
95+
})
96+
.then(buf =>
97+
t.deepEqual(buf, Buffer.from('hello', 'utf8'), 'got response')
98+
)
99+
})
100+
101+
test('stream body param', t => {
102+
tnock(t, OPTS.config.get('registry'))
103+
.matchHeader('content-type', ctype => {
104+
t.equal(ctype[0], 'application/octet-stream', 'content-type automatically set')
105+
return ctype[0] === 'application/octet-stream'
106+
})
107+
.post('/hello')
108+
.reply(200, (uri, reqBody) => {
109+
t.deepEqual(JSON.parse(reqBody), {
110+
hello: 'world'
111+
}, 'got the stringified version of the body')
112+
return reqBody
113+
})
114+
const stream = new PassThrough()
115+
setImmediate(() => stream.end(JSON.stringify({hello: 'world'})))
116+
const opts = Object.assign({
117+
method: 'POST',
118+
body: stream
119+
}, OPTS)
120+
return fetch('/hello', opts)
121+
.then(res => {
122+
t.equal(res.status, 200)
123+
return res.json()
124+
})
125+
.then(json => t.deepEqual(json, {hello: 'world'}))
126+
})
127+
128+
test('json()', t => {
129+
tnock(t, OPTS.config.get('registry'))
130+
.get('/hello')
131+
.reply(200, {hello: 'world'})
132+
return fetch.json('/hello', OPTS)
133+
.then(json => t.deepEqual(json, {hello: 'world'}, 'got json body'))
134+
})
135+
136+
test('method configurable', t => {
137+
tnock(t, OPTS.config.get('registry'))
138+
.delete('/hello')
139+
.reply(200)
140+
const opts = Object.assign({
141+
method: 'DELETE'
142+
}, OPTS)
143+
return fetch('/hello', opts)
144+
.then(res => {
145+
t.equal(res.status, 200, 'successfully used DELETE method')
146+
})
147+
})
148+
48149
test('pickRegistry() utility')
49150

50151
// TODO

0 commit comments

Comments
 (0)