Manoj Sethi
Manoj Sethi

Reputation: 2038

Unknown type "Upload" - Apollo Server Express with graphql-upload Node 14

I am working with GraphQL and is facing an issue with File Upload. My Node version is v14.16.0

I am getting error as below

Error: Unknown type "Upload". Did you mean "Float"?

Below are the package version installed

Package versions

"dependencies": {
    "apollo-server-express": "^2.23.0",
    "bcryptjs": "^2.4.3",
    "compression": "^1.7.4",
    "consola": "^2.15.3",
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "graphql-upload": "^11.0.0",
    "jsonwebtoken": "^8.5.1",
    "mongoose": "^5.12.5",
    "nodemon": "^2.0.7",
    "yup": "^0.32.9"
  }

Below is my server setup done with apollo-server-express and graphql-upload package

import express from "express";
import consola from "consola";
import { ApolloServer } from "apollo-server-express";
const { error, success } = consola;
import { PORT } from "./config/index.js";
import { typeDefs, resolvers } from "./graphql/index.js";
import * as AppModels from "./models/index.js";
import compression from "compression";
import { graphqlUploadExpress } from "graphql-upload";
//Initialize the app
const app = express();
app.use(compression());
app.use(
  graphqlUploadExpress({
    maxFileSize: 30000000,
    maxFiles: 20,
  })
);

const server = new ApolloServer({
  typeDefs,
  resolvers,
  uploads: false,
  context: {
    ...AppModels,
  },
});
app.use(express.static("public"));

server.applyMiddleware({ app });
app.listen(PORT, () => {
  success({
    badge: true,
    message: `Server started at ${PORT}`,
  });
});

Here are my type definition for imageUpload Mutation

import { gql } from "apollo-server-express";
export default gql`
  extend type Mutation {
    imageUploader(file: Upload!): String!
  }
`;

My resolver looks like this

import { createWriteStream } from "fs";
import { parse, join } from "path";
import { URL } from "../../config/index.js";
export default {
  Mutation: {
    imageUploader: async (_, { file }) => {
      let { filename, createReadStream } = await file;
      let stream = createReadStream();
      let { name, ext } = parse(filename);
      name = name.replace(/([^a-z0-9 ]+)/gi, "-").replace(" ", "_");
      let serverFile = `D:/${name}${ext}`;
      let writeStream = await createWriteStream(serverFile);
      await stream.pipe(writeStream);
      //serverFile = `${URL}/${serverFile.split("uploads")[1]}`;
      return serverFile;
    },
  },
};

Upvotes: 1

Views: 2300

Answers (2)

sachintha dilshan
sachintha dilshan

Reputation: 121

I'm using NODE 14

import {ApolloServer} from "apollo-server-express";
...
// If you want to see uploaded images, then you need to add these commands and, 
// create a folder to upload images name like 'uploads'

const app = express();
app.use(express.static(join(__dirname, './uploads')));
app.use(graphqlUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }));
const httpServer = http.createServer(app);

const server = new ApolloServer({
uploads: false,   // --------- use this
typeDefs,
resolvers,
plugins: [IN_PROD ? ApolloServerPluginLandingPageGraphQLPlayground() : 
ApolloServerPluginLandingPageDisabled(),
    ApolloServerPluginDrainHttpServer({httpServer})],
context: {
    ...AppModels
  }
});

after that, in typeDefs,

import { gql } from "apollo-server-express";

export default gql`
  scalar Upload // ---- use this


extend type Mutation {
    imageUploader(file: Upload!): String!
   }
`;

after that, In resolvers

import {parse, join} from 'path';
import {createWriteStream} from 'fs';
import {URL} from "../../../config";
import {GraphQLUpload} from "graphql-upload";

export default {
   Upload: GraphQLUpload, // ----- use this

Query: {
    info: () => "Hello i am image resolver methods."
 },
Mutation: {
    imageUploader: async (_, {file}) => {
        try {
            let {
                filename,
                createReadStream
            } = await file;
            let stream = createReadStream();

            let {
                ext,
                name
            } = parse(filename);

            name = name.replace(/([^a-z0-9 ]+)/gi, '-').replace(' ', '_');

            let serverFile = join(__dirname, 
            `../../../uploads/${name}-${Date.now()}${ext}`);

            let writeStream = await createWriteStream(serverFile);
            await stream.pipe(writeStream);

            let lastPath = serverFile.split('uploads')[1];
            lastPath = lastPath.replace('\\', '/');
            serverFile = `${URL}${lastPath}`;

            return serverFile;
        } catch (e) {
            console.log("ERROR UPLOAD A IMAGE", e);
            throw e;
           }
        }
     }
  }

Github link

Upvotes: 0

Manoj Sethi
Manoj Sethi

Reputation: 2038

Well this is for anybody who faces the situation

As we are using the graphl-upload package so we need to define the custom scalar in typedef and assign the Upload type in resolver.

So now my typedef looks like this. Notice the code scalar Upload

import { gql } from "apollo-server-express";
export default gql`
  scalar Upload
  extend type Mutation {
    imageUploader(file: Upload!): String!
  }
`;

After typedef changes we need to define a resolver for that scalar. So now the resolver looks like this

import { createWriteStream } from "fs";
import { GraphQLUpload } from "graphql-upload";
import { parse, join } from "path";
import { URL } from "../../config/index.js";
export default {
  Upload: GraphQLUpload,
  Mutation: {
    imageUploader: async (_, { file }) => {
      let { filename, createReadStream } = await file;
      let stream = createReadStream();
      let { name, ext } = parse(filename);
      name = name.replace(/([^a-z0-9 ]+)/gi, "-").replace(" ", "_");
      let serverFile = `D:/${name}${ext}`;
      let writeStream = await createWriteStream(serverFile);
      await stream.pipe(writeStream);
      //serverFile = `${URL}/${serverFile.split("uploads")[1]}`;
      return serverFile;
    },
  },
};

Above code helped me in getting pass that issue.

Upvotes: 4

Related Questions