How to Handle File Uploads in GraphQL
Handling file uploads in GraphQL requires a different approach compared to traditional REST APIs. Since GraphQL is designed to work with JSON, uploading files involves using a multipart request format. This guide will explain how to implement file uploads in a GraphQL API using the graphql-upload
package.
1. Setting Up the Environment
To handle file uploads in a GraphQL server, you need to install the graphql-upload
package along with your GraphQL server library (e.g., Apollo Server or Express-GraphQL).
Installation
npm install graphql-upload
2. Configuring the GraphQL Server
After installing the package, you need to configure your GraphQL server to use the upload middleware. Below is an example using Apollo Server:
Sample Server Setup
const { ApolloServer } = require('apollo-server');
const { graphqlUploadExpress } = require('graphql-upload');
const { gql } = require('apollo-server');
// Define the schema
const typeDefs = gql`
scalar Upload
type File {
filename: String!
mimetype: String!
encoding: String!
}
type Mutation {
uploadFile(file: Upload!): File!
}
`;
// Define the resolvers
const resolvers = {
Upload: require('graphql-upload').GraphQLUpload,
Mutation: {
uploadFile: async (parent, { file }) => {
const { createReadStream, filename, mimetype, encoding } = await file;
const stream = createReadStream();
// Here you can save the file to your desired location
// For example, using fs to write the file
// 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);
// });
return { filename, mimetype, encoding };
},
},
};
// Create the Apollo Server
const server = new ApolloServer({
typeDefs,
resolvers,
uploads: false, // Disable built-in uploads to use middleware
});
// Apply middleware for file uploads
server.applyMiddleware({
app,
path: '/graphql',
cors: true,
});
// Start the server
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
3. Client-Side File Upload
To upload a file from the client side, you can use a form with an input
of type file
. Below is an example using the apollo-client
library to send a file upload request:
Sample Client Code
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
import { createUploadLink } from 'apollo-upload-client';
// Create an Apollo Client instance with upload link
const client = new ApolloClient({
link: createUploadLink({ uri: 'http://localhost:4000/graphql' }),
cache: new InMemoryCache(),
});
// Function to handle file upload
const uploadFile = async (file) => {
const UPLOAD_FILE = gql`
mutation($file: Upload!) {
uploadFile(file: $file) {
filename
mimetype
encoding
}
}
`;
const { data } = await client.mutate({
mutation: UPLOAD_FILE,
variables: { file },
});
console.log('File uploaded:', data.uploadFile);
};
// HTML form to select and upload a file
const form = document.getElementById('uploadForm');
form.addEventListener('submit', async (event) => {
event.preventDefault();
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
await uploadFile(file);
});
4. Sample HTML Form
Here’s a simple HTML form to allow users to select a file for upload:
<form id="uploadForm">
<input type="file" id="fileInput">
<button type="submit">Upload File</button>
</form>
Conclusion
Handling file uploads in GraphQL requires the use of multipart requests and specific libraries like graphql-upload
. By following the steps outlined above, you can successfully implement file uploads in your GraphQL API, allowing clients to send files alongside their queries and mutations. This approach maintains the benefits of GraphQL while accommodating the need for file handling.