File Uploads with Apollo Server
Learn how to upload files with Apollo Server
How it works
The upload functionality follows the GraphQL multipart form requests specification. Two parts are needed to make the upload work correctly. The server and the client:
The Client: On the client, file objects are mapped into a mutation and sent to the server in a multipart request.
The Server: The multipart request is received. The server processes it and provides an upload argument to a resolver. In the resolver function, the upload promise resolves an object.
Server Configuration
The default option for enabling file uploads in Apollo Server involves creating a schema and using the Upload
type like so:
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
scalar Upload
type File {
filename: String!
mimetype: String!
encoding: String!
}
type Query {
uploads: [File]
}
type Mutation {
singleUpload(file: Upload!): File!
}
`;
Apollo Server 1.0 we have to add the Upload
scalar to the schema.
Apollo Server 2.0 automatically adds the Upload
scalar to the schema, when you are not setting the schema manually.
Resolver implementation
Earlier on, I mentioned that the server returns an upload promise that resolves an object. The object contains the following:
- stream: The upload stream manages streaming the file(s) to a filesystem or any storage location of your choice. e.g. S3, Azure, Cloudinary, e.t.c.
- filename: The name of the uploaded file(s).
- mimetype: The MIME type of the file(s) such as
text/plain
,application/pdf
, etc. - encoding: The file encoding such as UTF-8.
const resolvers = {
Query: {
files: () => {
// Return the record of files uploaded from your DB or API or filesystem.
}
},
Mutation: {
async singleUpload(parent, { file }) {
const { stream, filename, mimetype, encoding } = await file;
// 1. Validate file metadata.
// 2. Stream file contents into cloud storage:
// https://nodejs.org/api/stream.html
// 3. Record the file upload in your DB.
// const id = await recordFile( … )
return { filename, mimetype, encoding };
}
},
};
In the code above, the file can be validated after the promise resolves. If the file size or type is right (depending on the validation technique), it can be streamed into cloud storage like Cloudinary and the returned link can be stored in a database. Otherwise an Apollo error can be thrown within the resolver.
Note: When usingtypeDefs
, Apollo Server addsscalar Upload
to your schema, so any existing declaration ofscalar Upload
in the type definitions should be removed. If you create your schema withmakeExecutableSchema
and pass it toApolloServer
constructor using theschema
param, make sure to includescalar Upload
.
References:
https://blog.apollographql.com/file-uploads-with-apollo-server-2-0-5db2f3f60675
https://www.apollographql.com/docs/apollo-server/data/file-uploads/