File Uploads with Apollo Server 2.0

Learn how to upload files with Apollo Server and set it up on the client.

Prosper Otemuyiwa
Apollo GraphQL
4 min readJul 3, 2018

--

In web applications, one of the most common requirements is file uploads. For a while now, the question being asked around the GraphQL community is “How does one perform file uploads in GraphQL itself?” The community turned to the GraphQL specification and reference implementation but found no answers because the specification has no provisions for file uploads.

There are several ways you could upload files when using a GraphQL API, for example sending the file to Cloudinary or S3 directly and passing the returned URL through a GraphQL mutation. However, coordinating these multiple requests might be hard to manage. One of the simplest ways of achieving file uploads in a single request is to base64-encode a file and send as a string variable in a mutation. Another option is to send file(s) in the same request as your mutation, which I’ll cover in this post!

Jayden Seric, a JavaScript engineer and GraphQL community member came up with a specification for GraphQL multipart form requests(file uploads) and also provided a reference implementation.

At Apollo, we are committed to making sure you have the best developer experience throughout your GraphQL journey.

We decided to incorporate the much requested file uploads feature into Apollo Server 2.0, thanks to inspiration from the wonderful apollo-upload-server package by Jayden. With GraphQL, we are achieving a single paradigm of data management. Just how Apollo Client merges remote and local data. Apollo Server enables you to combine multiple previously orthogonal data sources into a single paradigm. This post being about the specific case of file uploads and JSON data.

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.

Stay with me! The resolver section will reveal what the object contains and how you can use it.

Server Configuration

The default option for enabling file uploads in Apollo Server 2.0 involves creating a schema and using the Upload type like so:

The first question you’re most likely to ask from the schema observation above is “Where does Upload scalar type come from?” Don’t fret. It is added automatically by Apollo Server.

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:

  1. 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.
  2. filename: The name of the uploaded file(s).
  3. mimetype: The MIME type of the file(s) such as text/plain, application/octet-stream, etc.
  4. encoding: The file encoding such as UTF-8.
Resolver implementation

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.

Client Setup

If the user is expected to upload files from an interactive client UI, then you need to install the apollo-upload-client package from npm. And deal with single and multiple files from the client.

Single file upload example from the client:

Single file upload

Use FileList, File, Blob or ReactNativeFile instances anywhere within query or mutation input variables to send a GraphQL multipart request. In the example above, we operated a single file upload, thus using File.

The user selects a file, the client validates the file and immediately sends a multipart request in the same request as the uploadFile mutation to the server.

Check out the file uploads documentation for more information on multiple and blob file uploads from the client.

Try it out

A full-stack working example created by Jayden is available on GitHub. Clone and try it out. Feel free to provide feedback.

To keep learning, check out our new best practices guides about topics like schema design, versioning, access control, and more.

Finally, I hope you’ll also join us at the 3rd annual GraphQL Summit on Nov 7–8 in San Francisco. With over 800 attendees expected, it’s the largest GraphQL developer event in the world. Super early bird tickets are selling fast, so register today to reserve your spot!

--

--

Prosper Otemuyiwa
Apollo GraphQL

Developer & Technology Advocate. Writer of all things Technical & Magical. Software Craftsman.