Allowing users upload files from your mobile app

Enabling file uploads on the server

Voyager Server provides support for uploading binary data along with the GraphQL queries. The implementation relies on upstream Apollo Server capabilities.

The upload functionality uses the GraphQL multipart form requests specification. File upload needs to be implemented on both server and client:

  1. On the client HTML FileList objects are mapped into a mutation and sent to the server in a multipart request.

  2. On the server: The multipart request is handled. The server processes it and provides an upload argument to a resolver. In the resolver function, the upload promise resolves an object.

File upload is based on graphql-multipart-request-spec.
Procedure

To enable file uploads, create a schema and use the Upload scalar. For example:

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

const typeDefs = gql`
  type File {
    filename: String!
    mimetype: String!
    encoding: String!
  }
  type Query {
    uploads: [File]
  }
  type Mutation {
    singleUpload(file: Upload!): File!
  }
`;

The following schema enables file uploads. The Upload scalar will be injected as one of the arguments in the resolvers. The Upload scalar contains all file metadata and a Readable Stream that can be used to save the file to a specific location.

    async singleUpload(parent, { file }) {
      const { stream, filename, mimetype, encoding } = await file;
      // Save file and return required metadata
    }

See Official Apollo blog post for more information.

Implementing file upload on the client

Voyager Client provides support for uploading binary data along with the GraphQL queries. The binary upload implementation uses the apollo-upload-client package built by the Apollo community.

Introduction

The upload functionality uses the GraphQL multipart form requests specification. The File upload needs to be implemented on both server and client:

  1. On the client HTML FileList objects are mapped into a mutation and sent to the server in a multipart request.

  2. On the server: The multipart request is handled. The server processes it and provides an upload argument to a resolver. In the resolver function, the upload promise resolves an object.

File upload is based on graphql-multipart-request-spec.

Enabling File Upload

File upload feature needs to be enabled by passing fileUpload flag to config object:

const config = {
  ...
  fileUpload: true
  ...
};

//create a new client

Uploading Files from GraphQL

File upload capability adds a new GraphQL scalar Upload that can be used for mutations that operate on binary data. The Upload scalar maps html FileList HTML5 object in GraphQL schemas. The first step required to work with binary uploads is to write mutation that will contain Upload scalar. The following example demonstrates how to upload a profile picture:

import gql from 'graphql-tag'
import { Mutation } from 'react-apollo'

export const UPLOAD_PROFILE = gql`
mutation changeProfilePicture($file: Upload!) {
  changeProfilePicture(file: $file) {
    filename
    mimetype
    encoding
  }
}
`;

Executing mutations

The Upload scalar will be mapped to object returned from HTML file input.

The following example shows file upload in a React application.

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