Graphql-yoga: Getting createReadStream is not a function when uploading a file

Created on 24 Aug 2019  Â·  10Comments  Â·  Source: dotansimha/graphql-yoga

graphql-yoga: 1.18.2
react-native: 0.60.4
apollo-upload-client: 11.0.0

Hi there, after updating to 1.18 I can no longer upload files. I'm trying to upload a file using react-native and apollo-upload-client. Here's what the mutation variable looks like on the client:

data: {
    file: new ReactNativeFile({
      uri,
      type: typeForSaving,
      name: 'photo-1.jpeg'
    })
}

And here's the server code:

Schema:

scalar Upload

type Mutation {
    contentSingleUpload(data: ContentSingleUploadInput!): SingleUploadPayload!
}

input ContentSingleUploadInput {
    file: Upload
}

Resolver:

async contentSingleUpload(parent, args, ctx, info) {
    const fileResult = await processUpload(args.data.file)
}

const processUpload = async upload => {
    const { createReadStream, filename, mimetype, encoding } = await upload

    const stream = createReadStream()
    ...
}

The request fails with createReadStream is not a function and when I try to look at args.data.file I am seeing:
image

Thanks in advance.

Most helpful comment

@stephensamra remplace createReadStream with just stream
and remove the line const stream = createReadStream()

All 10 comments

@stephensamra remplace createReadStream with just stream
and remove the line const stream = createReadStream()

@aarabmed Thanks for the reply. stream was replaced with createReadStream in v1.18.0. See https://github.com/prisma/graphql-yoga/pull/462#issuecomment-428424647

was this ever resolved?

Anyone with the solution?

I'm in the process of migrating to apollo-server. I'll report back here whether apollo-server has the same issue.

for me when I use stream it says "File upload property ‘stream’ is deprecated. Use ‘createReadStream()’ instead."

this is the approach i use to make images or files upload , hope it helps someone

  • first a function that handles the saving process and it return a promise
const storeFS = ({ stream, filename,mimetype }) => {
                const id = uuid()
                const path = `${UPLOADED_IMAGES}/${id}-${filename}`
                return new Promise((resolve, reject) =>{
                stream
                    .on('error', error => {

                        if (stream.truncated)
                        // Delete the truncated file.
                        fs.unlinkSync(path)
                        throw new Error("Please select a file with size 700 KB or less")
                        reject(error)
                    })
                    .pipe(fs.createWriteStream(path))
                    .on('error', error => reject(error))
                    .on('finish', () => resolve({
                            _id:uuid(),
                            filename:`${id}-${filename}`,
                            mimetype:mimetype,
                            path:path
                        }))
                })
            }

second :

  • this function does couple things :
    >create a directory where to save the image if its not existed
    >check for file type
    >return the result of storeFS() function declared above
 let process_upload = async upload => {
                mkdirp.sync(UPLOADED_IMAGES)
                let { filename, mimetype, encoding, createReadStream } = await upload

                if(mimetype !== 'image/jpeg' && mimetype !=='image/png'){
                 throw new Error("Please select a file with one of the following formats: jpeg, jpg, png");

                }     

                const stream = createReadStream()
                return storeFS({ stream, filename,mimetype })

            }
  • Third and last part :

    calling promisesAll function which take all the images retrieved from image input , which for me is images and do a loop for each one as promise

    ```
    let { resolve, reject } = await promisesAll.all(
    images.map(process_upload)
    )

                    if (reject.length)
                    reject.forEach(({ name, message }) =>
    
                    console.error(`Name!!: ${name}:  Message!!:${message}`)
                    )
                    res = resolve
    

```
res will be the response data you'll receive back if everything worked as it should

i hope this code is clear enough
ps: packages i used are

const promisesAll = require ('promises-all');
const mkdirp = require('mkdirp')
const fs = require('fs')
const path = require('path');

Anyone with the solution?

while working on nexus solution was to call file inside file.
try {
const {
file: { filename, mimetype, encoding, createReadStream },
} = file;
console.log("FIle 1", file);
let stream = createReadStream();

In my case, I was using Antd Upload and was sending the whole object returns from Upload component, but we only need to send originFileObj

file.originFileObj

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cj picture cj  Â·  3Comments

asci picture asci  Â·  3Comments

ramonmulia picture ramonmulia  Â·  3Comments

chakrihacker picture chakrihacker  Â·  5Comments

joshhopkins picture joshhopkins  Â·  3Comments