1414 * limitations under the License.
1515 */
1616
17+ import axios from 'axios' ;
1718import extend = require( 'extend' ) ;
18- import request = require( 'request' ) ;
19+ import FormData = require( 'form-data' ) ;
20+ import querystring = require( 'querystring' ) ;
1921import { PassThrough as readableStream } from 'stream' ;
2022import { buildRequestFileObject , getMissingParams , isEmptyObject , isFileParam } from './helper' ;
2123
@@ -46,7 +48,7 @@ function parsePath(path: string, params: Object): string {
4648 * @private
4749 * @returns {request.RequestCallback }
4850 */
49- export function formatErrorIfExists ( cb : Function ) : request . RequestCallback {
51+ export function formatErrorIfExists ( cb : Function ) {
5052 return ( error , response , body ) => {
5153 // eslint-disable-line complexity
5254
@@ -74,14 +76,14 @@ export function formatErrorIfExists(cb: Function): request.RequestCallback {
7476
7577 // for api-key services
7678 if ( response . statusMessage === 'invalid-api-key' ) {
77- const error = {
79+ const err = {
7880 error : response . statusMessage ,
7981 code : response . statusMessage === 'invalid-api-key' ? 401 : 400 ,
8082 } ;
8183 if ( response . headers ) {
82- error [ globalTransactionId ] = response . headers [ globalTransactionId ] ;
84+ err [ globalTransactionId ] = response . headers [ globalTransactionId ] ;
8385 }
84- cb ( error , null ) ;
86+ cb ( err , null ) ;
8587 return ;
8688 }
8789
@@ -141,36 +143,11 @@ export function formatErrorIfExists(cb: Function): request.RequestCallback {
141143 * @throws {Error }
142144 */
143145export function sendRequest ( parameters , _callback ) {
144- let missingParams = null ;
145146 const options = extend ( true , { } , parameters . defaultOptions , parameters . options ) ;
146- const { path, body, form, formData, qs } = options ;
147-
148- // Missing parameters
149- if ( parameters . options . requiredParams ) {
150- // eslint-disable-next-line no-console
151- console . warn (
152- new Error (
153- 'requiredParams set on parameters.options - it should be set directly on parameters'
154- )
155- ) ;
156- }
147+ const { path, body, form, formData, qs, method } = options ;
148+ let { url, headers } = options ;
157149
158- missingParams = getMissingParams (
159- parameters . originalParams || extend ( { } , qs , body , form , formData , path ) ,
160- parameters . requiredParams
161- ) ;
162-
163- if ( missingParams ) {
164- if ( typeof _callback === 'function' ) {
165- return _callback ( missingParams ) ;
166- } else {
167- const errorStream = new readableStream ( ) ;
168- setTimeout ( ( ) => {
169- errorStream . emit ( 'error' , missingParams ) ;
170- } , 0 ) ;
171- return errorStream ;
172- }
173- }
150+ const multipartForm = new FormData ( ) ;
174151
175152 // Form params
176153 if ( formData ) {
@@ -179,59 +156,111 @@ export function sendRequest(parameters, _callback) {
179156 // Remove non-valid inputs for buildRequestFileObject,
180157 // i.e things like {contentType: <contentType>}
181158 Object . keys ( formData ) . forEach ( key => {
182- // tslint:disable-next-line:no-unused-expression
183- ( formData [ key ] == null ||
159+ if ( formData [ key ] == null ||
184160 isEmptyObject ( formData [ key ] ) ||
185- ( formData [ key ] . hasOwnProperty ( 'contentType' ) && ! formData [ key ] . hasOwnProperty ( 'data' ) ) ) &&
161+ ( formData [ key ] . hasOwnProperty ( 'contentType' ) && ! formData [ key ] . hasOwnProperty ( 'data' ) ) ) {
186162 delete formData [ key ] ;
163+ }
187164 } ) ;
188165 // Convert file form parameters to request-style objects
189- Object . keys ( formData ) . forEach (
190- key => formData [ key ] . data != null && ( formData [ key ] = buildRequestFileObject ( formData [ key ] ) )
191- ) ;
166+ Object . keys ( formData ) . forEach ( key => {
167+ if ( formData [ key ] . data != null ) {
168+ formData [ key ] = buildRequestFileObject ( formData [ key ] ) ;
169+ }
170+ } ) ;
192171
193172 // Stringify arrays
194- Object . keys ( formData ) . forEach (
195- key => Array . isArray ( formData [ key ] ) && ( formData [ key ] = formData [ key ] . join ( ',' ) )
196- ) ;
173+ Object . keys ( formData ) . forEach ( key => {
174+ if ( Array . isArray ( formData [ key ] ) ) {
175+ formData [ key ] = formData [ key ] . join ( ',' ) ;
176+ }
177+ } ) ;
197178
198179 // Convert non-file form parameters to strings
199- Object . keys ( formData ) . forEach (
200- key =>
201- ! isFileParam ( formData [ key ] ) &&
180+ Object . keys ( formData ) . forEach ( key => {
181+ if ( ! isFileParam ( formData [ key ] ) &&
202182 ! Array . isArray ( formData [ key ] ) &&
203- typeof formData [ key ] === 'object' &&
204- ( formData [ key ] = JSON . stringify ( formData [ key ] ) )
205- ) ;
183+ typeof formData [ key ] === 'object' ) {
184+ ( formData [ key ] = JSON . stringify ( formData [ key ] ) ) ;
185+ }
186+ } ) ;
187+
188+ // build multipart form data
189+ Object . keys ( formData ) . forEach ( key => {
190+ // handle files differently to maintain options
191+ if ( formData [ key ] . value ) {
192+ multipartForm . append ( key , formData [ key ] . value , formData [ key ] . options ) ;
193+ } else {
194+ multipartForm . append ( key , formData [ key ] ) ;
195+ }
196+ } ) ;
206197 }
207198
208199 // Path params
209- options . url = parsePath ( options . url , path ) ;
210- delete options . path ;
200+ url = parsePath ( url , path ) ;
211201
212202 // Headers
213- options . headers = extend ( { } , options . headers ) ;
203+ headers = extend ( { } , headers ) ;
214204 if ( ! isBrowser ) {
215- options . headers [ 'User-Agent' ] = `${ pkg . name } -nodejs-${ pkg . version } ;${ options . headers [
216- 'User-Agent'
217- ] || '' } `;
205+ headers [ 'User-Agent' ] = `${ pkg . name } -nodejs-${ pkg . version } ;${ headers [ 'User-Agent' ] || '' } ` ;
218206 }
219207
220- // Query params
221- if ( options . qs && Object . keys ( options . qs ) . length > 0 ) {
222- Object . keys ( options . qs ) . forEach (
223- key => Array . isArray ( options . qs [ key ] ) && ( options . qs [ key ] = options . qs [ key ] . join ( ',' ) )
208+ // Convert array-valued query params to strings
209+ if ( qs && Object . keys ( qs ) . length > 0 ) {
210+ Object . keys ( qs ) . forEach (
211+ key => Array . isArray ( qs [ key ] ) && ( qs [ key ] = qs [ key ] . join ( ',' ) )
224212 ) ;
225- options . useQuerystring = true ;
226213 }
227214
228215 // Add service default endpoint if options.url start with /
229- if ( options . url . charAt ( 0 ) === '/' ) {
230- options . url = parameters . defaultOptions . url + options . url ;
216+ if ( url && url . charAt ( 0 ) === '/' ) {
217+ url = parameters . defaultOptions . url + url ;
218+ }
219+
220+ let data = body ;
221+
222+ if ( form ) {
223+ data = querystring . stringify ( form ) ;
224+ headers [ 'Content-type' ] = 'application/x-www-form-urlencoded' ;
225+ }
226+
227+ if ( formData ) {
228+ data = multipartForm ;
229+ // form-data generates headers that MUST be included or the request will fail
230+ headers = extend ( true , { } , headers , multipartForm . getHeaders ( ) ) ;
231231 }
232232
233- // Compression support
234- options . gzip = true ;
233+ const axiosObject = {
234+ url,
235+ method,
236+ headers,
237+ params : qs ,
238+ data,
239+ responseType : options . responseType || 'json' ,
240+ paramsSerializer : params => {
241+ return querystring . stringify ( params ) ;
242+ }
243+ } ;
235244
236- return request ( options , formatErrorIfExists ( _callback ) ) ;
245+ axios ( axiosObject )
246+ . then ( res => {
247+ _callback ( null , res . data , res ) ;
248+ } )
249+ . catch ( error => {
250+ if ( error . response ) {
251+ // The request was made and the server responded with a status code
252+ // that falls out of the range of 2xx
253+ delete error . response . config ;
254+ delete error . response . request ;
255+ _callback ( error . response ) ;
256+ } else if ( error . request ) {
257+ // The request was made but no response was received
258+ // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
259+ // http.ClientRequest in node.js
260+ _callback ( error . request ) ;
261+ } else {
262+ // Something happened in setting up the request that triggered an Error
263+ _callback ( error . message ) ;
264+ }
265+ } ) ;
237266}
0 commit comments