0
0
GraphqlHow-ToBeginner · 4 min read

How to Upload Multiple Files in GraphQL: Syntax and Example

To upload multiple files in GraphQL, use the graphql-upload specification which supports multipart requests. Define your mutation to accept an array of Upload scalar types, then send files as an array in the request. This allows you to handle multiple file uploads in a single GraphQL mutation.
📐

Syntax

Use a mutation that accepts an array of Upload types. The Upload scalar handles file streams. The client sends files as multipart form data with a map linking files to variables.

  • mutation: Defines the operation to upload files.
  • files: [Upload!]!: An array of non-null files.
  • graphql-upload: Middleware or library to process multipart requests.
graphql
mutation UploadMultipleFiles($files: [Upload!]!) {
  uploadFiles(files: $files) {
    filename
    mimetype
    encoding
  }
}
💻

Example

This example shows a Node.js GraphQL server using graphql-upload to accept multiple files and return their details. The client sends files as an array in the files variable.

javascript
const { ApolloServer, gql } = require('apollo-server-express');
const { GraphQLUpload, graphqlUploadExpress } = require('graphql-upload');
const fs = require('fs');
const express = require('express');

const typeDefs = gql`
  scalar Upload

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

  type Mutation {
    uploadFiles(files: [Upload!]!): [File!]!
  }
`;

const resolvers = {
  Upload: GraphQLUpload,
  Mutation: {
    uploadFiles: async (_, { files }) => {
      const results = [];
      for await (const file of files) {
        const { filename, mimetype, encoding, createReadStream } = await file;
        // Example: save file to disk (optional)
        const stream = createReadStream();
        const path = `./uploads/${filename}`;
        await new Promise((resolve, reject) => {
          const writeStream = fs.createWriteStream(path);
          stream.pipe(writeStream);
          writeStream.on('finish', resolve);
          writeStream.on('error', reject);
        });
        results.push({ filename, mimetype, encoding });
      }
      return results;
    },
  },
};

const app = express();
app.use(graphqlUploadExpress());

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

server.start().then(() => {
  server.applyMiddleware({ app });
  app.listen({ port: 4000 }, () => {
    console.log(`Server ready at http://localhost:4000${server.graphqlPath}`);
  });
});
Output
Server ready at http://localhost:4000/graphql
⚠️

Common Pitfalls

  • Not using graphql-upload middleware causes file streams to be unavailable.
  • Defining the mutation to accept a single Upload instead of an array [Upload!]! limits to one file.
  • Forgetting to handle asynchronous file streams properly can cause errors or incomplete uploads.
  • Client must send files using multipart/form-data with correct map and operations fields; otherwise, uploads fail.
graphql
/* Wrong: single file upload only */
mutation UploadFile($file: Upload!) {
  uploadFile(file: $file) {
    filename
  }
}

/* Right: multiple files upload */
mutation UploadMultipleFiles($files: [Upload!]!) {
  uploadFiles(files: $files) {
    filename
  }
}
📊

Quick Reference

StepDescription
Define mutationUse an array of Upload scalar: files: [Upload!]!
Use graphql-uploadAdd middleware to parse multipart requests
Client requestSend files as multipart/form-data with map and operations
Handle streamsProcess each file stream asynchronously in resolver
Return infoReturn file metadata or URLs after upload

Key Takeaways

Use the Upload scalar array [Upload!]! in your mutation to accept multiple files.
Add graphql-upload middleware to your server to handle multipart file uploads.
Send files from the client as multipart/form-data with proper mapping to variables.
Process file streams asynchronously in your resolver to save or handle files.
Avoid defining mutations for single files if you need to upload multiple files.