From 28650db0eb76332835901f11bcdaaaab7dee1047 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Sat, 19 Jan 2019 15:51:34 -0800 Subject: [PATCH] fix: pipe streams directly to the request (#27) --- src/gaxios.ts | 11 ++++++-- test/test.getch.ts | 70 +++++++++++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/gaxios.ts b/src/gaxios.ts index e6f3e8b2..20c65dcd 100644 --- a/src/gaxios.ts +++ b/src/gaxios.ts @@ -15,6 +15,7 @@ import * as extend from 'extend'; import {Agent} from 'https'; import fetch, {Response} from 'node-fetch'; import * as qs from 'querystring'; +import * as stream from 'stream'; import {URL} from 'url'; import {GaxiosError, GaxiosOptions, GaxiosPromise, GaxiosResponse, Headers} from './common'; @@ -105,7 +106,9 @@ export class Gaxios { opts.headers = opts.headers || {}; if (opts.data) { - if (typeof opts.data === 'object') { + if (this.isReadableStream(opts.data)) { + opts.body = opts.data; + } else if (typeof opts.data === 'object') { opts.body = JSON.stringify(opts.data); opts.headers['Content-Type'] = 'application/json'; } else { @@ -157,6 +160,10 @@ export class Gaxios { return qs.stringify(params); } + private isReadableStream(obj: any): boolean { + return obj instanceof stream.Readable && typeof obj._read === 'function'; + } + private translateResponse(opts: GaxiosOptions, res: Response, data?: T): GaxiosResponse { // headers need to be converted from a map to an obj @@ -167,4 +174,4 @@ export class Gaxios { return {config: opts, data: data as T, headers, status: res.status}; } -} \ No newline at end of file +} diff --git a/test/test.getch.ts b/test/test.getch.ts index 301e20dd..7dd7a9d0 100644 --- a/test/test.getch.ts +++ b/test/test.getch.ts @@ -20,6 +20,7 @@ const assertRejects = require('assert-rejects'); const HttpsProxyAgent = require('https-proxy-agent'); import {Gaxios, GaxiosError, request, GaxiosOptions} from '../src'; import * as qs from 'querystring'; +import * as fs from 'fs'; nock.disableNetConnect(); @@ -126,6 +127,46 @@ describe('🥁 configuration options', () => { assert.deepStrictEqual(res.data, {}); }); + it('should use an https proxy if asked nicely', async () => { + sandbox.stub(process, 'env').value({https_proxy: 'https://fake.proxy'}); + const body = {hello: '🌎'}; + const scope = nock(url).get('/').reply(200, body); + const res = await request({url}); + scope.done(); + assert.deepStrictEqual(res.data, body); + assert.ok(res.config.agent instanceof HttpsProxyAgent); + }); + + it('should load the proxy from the cache', async () => { + sandbox.stub(process, 'env').value({HTTPS_PROXY: 'https://fake.proxy'}); + const body = {hello: '🌎'}; + const scope = nock(url).get('/').twice().reply(200, body); + const res1 = await request({url}); + const agent = res1.config.agent; + const res2 = await request({url}); + assert.strictEqual(agent, res2.config.agent); + scope.done(); + }); + + it('should include the request data in the response config', async () => { + const body = {hello: '🌎'}; + const scope = nock(url).post('/', body).reply(200); + const res = await request({url, method: 'POST', data: body}); + scope.done(); + assert.deepStrictEqual(res.config.data, body); + }); +}); + +describe('🎏 data handling', () => { + it('should accpet a ReadableStream as request data', async () => { + const body = fs.createReadStream('package.json'); + const contents = require('../../package.json'); + const scope = nock(url).post('/', contents).reply(200, {}); + const res = await request({url, method: 'POST', data: body}); + scope.done(); + assert.deepStrictEqual(res.data, {}); + }); + it('should accept a string in the request data', async () => { const body = {hello: '🌎'}; const encoded = qs.stringify(body); @@ -159,35 +200,6 @@ describe('🥁 configuration options', () => { scope.done(); assert.strictEqual(res.data, body); }); - - it('should use an https proxy if asked nicely', async () => { - sandbox.stub(process, 'env').value({https_proxy: 'https://fake.proxy'}); - const body = {hello: '🌎'}; - const scope = nock(url).get('/').reply(200, body); - const res = await request({url}); - scope.done(); - assert.deepStrictEqual(res.data, body); - assert.ok(res.config.agent instanceof HttpsProxyAgent); - }); - - it('should load the proxy from the cache', async () => { - sandbox.stub(process, 'env').value({HTTPS_PROXY: 'https://fake.proxy'}); - const body = {hello: '🌎'}; - const scope = nock(url).get('/').twice().reply(200, body); - const res1 = await request({url}); - const agent = res1.config.agent; - const res2 = await request({url}); - assert.strictEqual(agent, res2.config.agent); - scope.done(); - }); - - it('should include the request data in the response config', async () => { - const body = {hello: '🌎'}; - const scope = nock(url).post('/', body).reply(200); - const res = await request({url, method: 'POST', data: body}); - scope.done(); - assert.deepStrictEqual(res.config.data, body); - }); }); describe('🍂 defaults & instances', () => {