Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unknown type "Upload" in Apollo Server 2.6

I want to upload a file through GraphQL, and followed this article.

Here's the my schema:

extend type Mutation {
  bannerAdd(
    title: String!
    image: Upload
  ): ID
}

However when I run the app, this gives me this error:

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

Followed above article, Apollo Server will automatically generate Upload scalar, but why this is happening?

Also define Upload scalar manually also not working:

scalar Upload

...

Gives me this error:

Error: There can be only one type named "Upload".

Seems nothing wrong with my code. Is there an anything that I missed? Using [email protected], Apollo [email protected], Apollo Server [email protected] and [email protected].

Any advice will very appreciate it.

like image 818
modernator Avatar asked Oct 29 '25 16:10

modernator


2 Answers

Fix this problem with GraphQLUpload of Apollo Server for create a custom scalar called FileUpload.

Server setup with Apollo Server:

const {ApolloServer, gql, GraphQLUpload} = require('apollo-server');

const typeDefs = gql`
  scalar FileUpload

  type File {
    filename: String!
    mimetype: String!
    encoding: String!
  }

  type Query {
    uploads: [File]
  }

  type Mutation {
    singleUpload(file: FileUpload!): File!
  }
`;

const resolvers = {
  FileUpload: GraphQLUpload,
  Query: {
    uploads: (parent, args) => {},
  },
  Mutation: {
    singleUpload: async (_, {file}) => {
      const {createReadStream, filename, mimetype, encoding} = await file;
      const stream = createReadStream();

      // Rest of your code: validate file, save in your DB and static storage

      return {filename, mimetype, encoding};
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen().then(({url}) => {
  console.log(`🚀 Server ready at ${url}`);
});

Client Setup with Apollo Client and React.js:

You need to install the apollo-upload-client package too.

import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient, InMemoryCache, ApolloProvider, gql, useMutation } from '@apollo/client';
import { createUploadLink } from 'apollo-upload-client';

const httpLink = createUploadLink({
  uri: 'http://localhost:4000'
});

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache()
});


const UPLOAD_FILE = gql`
  mutation uploadFile($file: FileUpload!) {
    singleUpload(file: $file) {
      filename
      mimetype
      encoding
    }
  }
`;

function FileInput() {
  const [uploadFile] = useMutation(UPLOAD_FILE);

  return (
    <input
      type="file"
      required
      onChange={({target: {validity, files: [file]}}) =>
        validity.valid && uploadFile({variables: {file}})
      }
    />
  );
}

function App() {
  return (
    <ApolloProvider client={client}>
      <div>
        <FileInput/>
      </div>
    </ApolloProvider>
  );
}

ReactDOM.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>,
  document.getElementById('root')
);
like image 155
Eduardo Rengifo Avatar answered Nov 01 '25 05:11

Eduardo Rengifo


Here's the solution what I did, adding custom scalar named "FileUpload" and add GraphQLUpload as resolver like this:

import { GraphQLUpload } from 'graphql-upload';

export const resolvers = {
  FileUpload: GraphQLUpload
};

It works great, but it could be not perfect solution. Hope apollo fix this soon.

P.S. To upload file from your browser, you also need to set upload link in Apollo Client properly. Here's my code:

import { ApolloLink, split } from 'apollo-link';
import { createHttpLink } from 'apollo-link-http';
import { createUploadLink } from 'apollo-upload-client';

// Create HTTP Link
const httpLink = createHttpLink({
  uri: ...,
  credentials: 'include'
});

// Create File Upload Link
const isFile = value =>
  (typeof File !== 'undefined' && value instanceof File) || (typeof Blob !== 'undefined' && value instanceof Blob);
const isUpload = ({ variables }) => Object.values(variables).some(isFile);
const uploadLink = createUploadLink({
  uri: ...
  credentials: 'include'
});

const terminatingLink = (isUpload, uploadLink, httpLink);

const link = ApolloLink.from([<Some Other Link...>, <Another Other Link...>, terminatingLink]);

const apolloClient = new ApolloClient({
  link,
  ...
});
like image 43
modernator Avatar answered Nov 01 '25 06:11

modernator