jaydenseric / graphql-upload

Middleware and an Upload scalar to add support for GraphQL multipart requests (file uploads via queries and mutations) to various Node.js GraphQL servers.
https://npm.im/graphql-upload
MIT License
1.43k stars 131 forks source link

createReadStream is not a function #256

Closed maheraldous closed 3 years ago

maheraldous commented 3 years ago

Hello

I made a project for a few months ago and everything was working even the upload images but when I started the project again after a while and tried to upload a single image I get this error "createReadStream is not a function"

// index.js

const express = require('express');
const { graphqlUploadExpress } = require('graphql-upload');
const { ApolloServer, AuthenticationError } = require('apollo-server-express');
const { applyMiddleware } = require("graphql-middleware");
const { makeExecutableSchema } = require('graphql-tools');
...

  const schema = applyMiddleware(
    makeExecutableSchema({
      resolvers,
      typeDefs,
    }),
    // permissions
  );

  const app = express().use(
    graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }),
  );

  const server = new ApolloServer({
    schema,
    context: async ({ req }) => {
      if (req) {
        // console.log('req: ', req.headers);
        const userAuth = await getUser(req);
        // console.log('userAuth: ', userAuth);
        return {  
          userAuth,
        };
      }
    },
    playground: {
      endpoint: '/graphql',
      settings: {
        'editor.theme': 'dark',
      },
    },
    uploads: false // Don't use it as true when it is => v14 node
  });

  server.applyMiddleware({ app });

  let PORT = 4000;
  app.listen( PORT, (error) => {
    if (error) return error;
    console.log(`🚀 Server listening on port http://localhost:${PORT}`);
    console.log(`GraphQL at http://localhost:${PORT}${server.graphqlPath}`);
    // open(
    //     `http://localhost:${PORT}${schema.graphqlPath}`,
    //     // {app: 'firefox'}
    // );
  });
}
// schema/index.js

const { gql, AuthenticationError } = require('apollo-server-express');
const shortid = require('shortid');
const fs = require('fs-extra');
...

const storeUpload = async ({ stream, filename, mimetype, encoding }) => {
  const id = shortid.generate();
  // Delete those '?!,:;' from the filename
  filename = filename.replace(/[?!,:;]/g, '');
  // Replace the whitespace with this '-'
  filename = filename.replace(/[\s+]/g, '-');
  // Add random id to the filename
  filename = `${id}-${filename}`;
  // Create path to the file
  const path = `images/${filename}`;

  return await 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)
          fs.unlink(path, () => {
            reject(error);
          });
      })
      .pipe(fs.createWriteStream(path))
      .on("finish", () => resolve({
        // id,
        filename,
        path,
        mimetype,
        encoding
      }))
      .on("error", reject)
  );
};

const processUpload = async upload => {
  const { createReadStream, filename, mimetype, encoding } = await upload;
  if(upload.file.mimetype == 'image/jpeg' || upload.file.mimetype =='image/png' || upload.file.mimetype =='image/jpg') {
    const stream = await createReadStream();
    const file = await storeUpload({ stream, filename, mimetype, encoding });
    return file;
  } else {
    throw new Error("Please select a file with one of the following formats: jpeg, jpg, png");
  }
};

const typeDefs = gql`
  type File {
    _id: ID
    filename: String!
    path: String
    mimetype: String!
    encoding: String!
  }
  type Query {
    files: [File]
  }
  type Mutation {
    uploadFile(
      file: Upload!
    ): File!
  }
`;

const resolvers = {
Query: {
    files: async (_, args) => {
      const files = await FileMD.find()
      if (files == '') {
        return new Error(
          'There is no files'
        )
      }

      try {
        const filesArray = files.map(file => ({
          ...file._doc,
        }))
        return filesArray;
      } catch (err) {
        return err
      }
    },

Mutation: {
    uploadFile: async (_, args) => {
      console.log('args: ', args);
      console.log('args.file: ', args.file);
      fs.mkdir('images', { recursive: true }, err => {
        if (err) throw err;
      });

      const upload = await processUpload(args.file);
      console.log('upload: ', upload);
      const theFile = new FileMD(upload)
      const theFileSaved = await theFile.save()
      console.log('theFileSaved: ', theFileSaved);

      return theFileSaved;
    },}

}
}

Is the error there becuase that I updated from Node v12 to v14?

jaydenseric commented 3 years ago

I think you need to setup the GraphQLUpload scalar:

https://github.com/jaydenseric/graphql-upload#class-graphqlupload

maheraldous commented 3 years ago

Now I am getting this error https://github.com/apollographql/apollo-server/issues/3508

It seems that I have to move back to Node v12 from v14

But is there any way to upload files without going back.

I like the schema-first GraphQL but yours is code-first GraphQL so is there a way to do it with schema-first https://blog.logrocket.com/code-first-vs-schema-first-development-graphql/

maheraldous commented 3 years ago

You are right it works now thank you very much

jdgabriel commented 1 year ago

In new version, same problem here. Any solutions?

Error:

**TypeError: createReadStream is not a function**

Code:

@Mutation((_) => Boolean)
addProfilePicture(
  @Arg("picture", () => GraphQLUpload)
  { createReadStream, filename }: FileUpload
): Promise<boolean> {
  return new Promise(async (resolve, reject) =>
    createReadStream()
      .pipe(createWriteStream(__dirname + `./${filename}`))
      .on("finish", () => resolve(true))
      .on("error", () => reject(false))
  );
}
jdgabriel commented 1 year ago

I find solution when use Fastify/TypeGraphQL

https://github.com/MichalLytek/type-graphql/issues/37#issuecomment-1408637766

taikishiino commented 1 year ago

@jdgabriel @jaydenseric Hi👋 I have written a related issue here. https://github.com/meabed/graphql-upload-ts/issues/108

intellectualDarknet commented 1 year ago

i my case order of arguments wasn't coinciding in resolver and service. image image Make sure that you are passing correctly arguments and handling