@@ -18,6 +18,7 @@ import crossFetch from 'cross-fetch'
18
18
import { FileUpload } from 'graphql-upload'
19
19
20
20
// Imports:
21
+ import stream from 'stream'
21
22
import * as Oas3Tools from './oas_3_tools'
22
23
import { JSONPath } from 'jsonpath-plus'
23
24
import { debug } from 'debug'
@@ -32,6 +33,7 @@ const pubsub = new PubSub()
32
33
const translationLog = debug ( 'translation' )
33
34
const httpLog = debug ( 'http' )
34
35
const pubsubLog = debug ( 'pubsub' )
36
+ const uploadLog = debug ( 'fileUpload' )
35
37
36
38
// OAS runtime expression reference locations
37
39
const RUNTIME_REFERENCES = [ 'header.' , 'query.' , 'path.' , 'body' ]
@@ -325,7 +327,7 @@ export function getPublishResolver<TSource, TContext, TArgs>({
325
327
* If the operation type is Query or Mutation, create and return a resolver
326
328
* function that performs API requests for the given GraphQL query
327
329
*/
328
- export function getResolver < TSource , TContext , TArgs > ( {
330
+ export function getResolver < TSource , TContext , TArgs > ( {
329
331
operation,
330
332
argsFromLink = { } ,
331
333
payloadName,
@@ -578,13 +580,40 @@ export function getResolver<TSource, TContext, TArgs>({
578
580
} else if ( operation . payloadContentType === 'multipart/form-data' ) {
579
581
form = new FormData ( )
580
582
581
- Object . entries ( args [ sanePayloadName ] ) . forEach ( ( [ key , value ] ) => {
582
- // if (typeof value === 'object' && (value as Partial<FileUpload>).createReadStream) {
583
- // form.append(key, (value as FileUpload).createReadStream())
584
- // }
583
+ const formFieldsPayloadEntries = Object . entries ( args [ sanePayloadName ] ) ;
585
584
586
- form . append ( key , value )
587
- } )
585
+ ( await Promise . all ( formFieldsPayloadEntries . map ( ( [ _ , v ] ) => v ) ) )
586
+ . forEach ( ( fieldValue , idx ) => {
587
+ const fieldName = formFieldsPayloadEntries [ idx ] [ 0 ]
588
+
589
+ if ( typeof fieldValue === 'object' && Boolean ( ( fieldValue as Partial < FileUpload > ) . createReadStream ) ) {
590
+ const uploadingFile = fieldValue as FileUpload
591
+ const originalFileStream = uploadingFile . createReadStream ( )
592
+ const filePassThrough = new stream . PassThrough ( )
593
+
594
+ originalFileStream . on ( 'readable' , function ( ) {
595
+ let data
596
+ // tslint:disable-next-line:no-conditional-assignment
597
+ while ( data = this . read ( ) ) {
598
+ filePassThrough . write ( data )
599
+ }
600
+ } )
601
+
602
+ originalFileStream . on ( 'end' , ( ) => {
603
+ uploadLog ( `Upload for received file ${ uploadingFile . filename } completed` )
604
+ filePassThrough . end ( )
605
+ } )
606
+
607
+ uploadLog ( `Queuing upload for received file ${ uploadingFile . filename } ` )
608
+
609
+ form . append ( fieldName , filePassThrough , {
610
+ filename : uploadingFile . filename ,
611
+ contentType : uploadingFile . mimetype
612
+ } )
613
+ } else {
614
+ form . append ( fieldName , fieldValue )
615
+ }
616
+ } )
588
617
589
618
rawPayload = form
590
619
} else {
@@ -672,6 +701,11 @@ export function getResolver<TSource, TContext, TArgs>({
672
701
673
702
let response : Response
674
703
try {
704
+ // if is form, remove default content type and
705
+ // let fetch compute appropriate header content-type based off of form data
706
+ if ( form ) {
707
+ delete options . headers [ 'content-type' ]
708
+ }
675
709
response = await fetch ( url . toString ( ) , options )
676
710
} catch ( err ) {
677
711
httpLog ( err )
0 commit comments