Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

apollo-upload-server

jaydenseric54.7kMITdeprecated7.1.0

Please migrate to https://npm.im/graphql-upload (see https://git.io/fADhl).

Middleware and an Upload scalar to add support for GraphQL multipart requests (file uploads via queries and mutations) to various Node.js GraphQL servers.

apollo, server, graphql, file, upload, multipart, koa, express, esm, mjs

readme

Apollo upload logo

apollo-upload-server

npm version Build status

Middleware and an Upload scalar to add support for GraphQL multipart requests (file uploads via queries and mutations) to various Node.js GraphQL servers.

Support

The following environments are known to be compatible, or feature this package built in:

See also GraphQL multipart request spec server implementations.

Setup

Setup is necessary if your environment doesn’t feature this package built in (see Support).

To install apollo-upload-server and the graphql peer dependency from npm run:

npm install apollo-upload-server graphql

Use the apolloUploadKoa or apolloUploadExpress middleware just before GraphQL middleware. Alternatively, use processRequest to create custom middleware.

A schema built with separate SDL and resolvers (e.g. using makeExecutableSchema) requires the Upload scalar to be setup.

Usage

Clients implementing the GraphQL multipart request spec upload files as Upload scalar query or mutation variables. Their resolver values are promises that resolve file upload details for processing and storage. Files are typically streamed into cloud storage but may also be stored in the filesystem.

See the example API and client.

Tips

  • The process must have both read and write access to the directory identified by os.tmpdir().
  • The device requires sufficient disk space to buffer the expected number of concurrent upload requests.
  • Promisify and await file upload streams in resolvers or the server will send a response to the client before uploads are complete, causing a disconnect.
  • Handle file upload promise rejection and stream errors; uploads sometimes fail due to network connectivity issues or impatient users disconnecting.
  • Process multiple uploads asynchronously with Promise.all or a more flexible solution where an error in one does not reject them all.
  • Only use createReadStream() before the resolver returns; late calls (e.g. in an unawaited async function or callback) throw an error. Existing streams can still be used after a response is sent, although there are few valid reasons for not awaiting their completion.
  • Use stream.destroy() when an incomplete stream is no longer needed, or temporary files may not get cleaned up.

Architecture

The GraphQL multipart request spec allows a file to be used for multiple query or mutation variables (file deduplication), and for variables to be used in multiple places. GraphQL resolvers need to be able to manage independent file streams. As resolvers are executed asynchronously, it’s possible they will try to process files in a different order than received in the multipart request.

busboy parses multipart request streams. Once the operations and map fields have been parsed, Upload scalar values in the GraphQL operations are populated with promises, and the operations are passed down the middleware chain to GraphQL resolvers.

fs-capacitor is used to buffer file uploads to the filesystem and coordinate simultaneous reading and writing. As soon as a file upload’s contents begins streaming, its data begins buffering to the filesystem and its associated promise resolves. GraphQL resolvers can then create new streams from the buffer by calling createReadStream(). The buffer is destroyed once all streams have ended or closed and the server has responded to the request. Any remaining buffer files will be cleaned when the process exits.

API

Table of contents

class GraphQLUpload

A GraphQL Upload scalar that can be used in a GraphQLSchema. It’s value in resolvers is a promise that resolves file upload details for processing and storage.

Examples

Setup for a schema built with makeExecutableSchema.

import { makeExecutableSchema } from 'graphql-tools'
import { GraphQLUpload } from 'apollo-upload-server'

const typeDefs = `
  scalar Upload
`

const resolvers = {
  Upload: GraphQLUpload
}

export const schema = makeExecutableSchema({ typeDefs, resolvers })

A manually constructed schema with an image upload mutation.

import { GraphQLSchema, GraphQLObjectType, GraphQLBoolean } from 'graphql'
import { GraphQLUpload } from 'apollo-upload-server'

export const schema = new GraphQLSchema({
  mutation: new GraphQLObjectType({
    name: 'Mutation',
    fields: {
      uploadImage: {
        description: 'Uploads an image.',
        type: GraphQLBoolean,
        args: {
          image: {
            description: 'Image file.',
            type: GraphQLUpload
          }
        },
        async resolve(parent, { image }) {
          const { filename, mimetype, createReadStream } = await image
          const stream = createReadStream()
          // Promisify the stream and store the file, then…
          return true
        }
      }
    }
  })
})

function apolloUploadExpress

Creates Express middleware that processes GraphQL multipart requests using processRequest, ignoring non-multipart requests. It sets the request body to be similar to a conventional GraphQL POST request for following GraphQL middleware to consume.

Parameter Type Description
options UploadOptions GraphQL upload options.

Returns: function — Express middleware.

Examples

Basic express-graphql setup.

import express from 'express'
import graphqlHTTP from 'express-graphql'
import { apolloUploadExpress } from 'apollo-upload-server'
import schema from './schema'

express()
  .use(
    '/graphql',
    apolloUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }),
    graphqlHTTP({ schema })
  )
  .listen(3000)

function apolloUploadKoa

Creates Koa middleware that processes GraphQL multipart requests using processRequest, ignoring non-multipart requests. It sets the request body to be similar to a conventional GraphQL POST request for following GraphQL middleware to consume.

Parameter Type Description
options UploadOptions GraphQL upload options.

Returns: function — Koa middleware.

Examples

Basic graphql-api-koa setup.

import Koa from 'koa'
import bodyParser from 'koa-bodyparser'
import { errorHandler, execute } from 'graphql-api-koa'
import { apolloUploadKoa } from 'apollo-upload-server'
import schema from './schema'

new Koa()
  .use(errorHandler())
  .use(bodyParser())
  .use(apolloUploadKoa({ maxFileSize: 10000000, maxFiles: 10 }))
  .use(execute({ schema }))
  .listen(3000)

function processRequest

Processes a GraphQL multipart request. Used in apolloUploadKoa and apolloUploadExpress and can be used to create custom middleware.

Parameter Type Description
request IncomingMessage Node.js HTTP server request instance.
response ServerResponse Node.js HTTP server response instance.
options UploadOptions? GraphQL upload options.

Returns: Promise<GraphQLOperation | Array<GraphQLOperation>> — GraphQL operation or batch of operations for a GraphQL server to consume (usually as the request body).

Examples

How to import.

import { processRequest } from 'apollo-upload-server'

type FileUpload

File upload details, resolved from an Upload scalar promise.

Type: Object

Property Type Description
filename string File name.
mimetype string File MIME type. Provided by the client and can’t be trusted.
encoding string File stream transfer encoding.
createReadStream function Returns a Node.js readable stream of the file contents, for processing and storing the file. Multiple calls create independent streams. Throws if called after all resolvers have resolved, or after an error has interrupted the request.

type GraphQLOperation

A GraphQL operation object in a shape that can be consumed and executed by most GraphQL servers.

Type: Object

Property Type Description
query string GraphQL document containing queries and fragments.
operationName string | null? GraphQL document operation name to execute.
variables object | null? GraphQL document operation variables and values map.

See

type UploadOptions

GraphQL upload server options, mostly relating to security, performance and limits.

Type: Object

Property Type Description
maxFieldSize number? = 1000000 Maximum allowed non-file multipart form field size in bytes; enough for your queries.
maxFileSize number? = Infinity Maximum allowed file size in bytes.
maxFiles number? = Infinity Maximum allowed number of files.

changelog

apollo-upload-server changelog

7.1.0

Minor

Patch

  • Updated dev dependencies.

7.0.0

Major

  • The processRequest function now requires a http.ServerResponse instance as its second argument.
  • Replaced the previously exported error classes with http-errors and snapshot tested error details, via #105.
  • No longer exporting the SPEC_URL constant.

Minor

  • Upload scalar promises now resolve with a createReadStream method instead of a stream property, via #92.
  • Accessing an Upload scalar promise resolved stream property results in a deprecation warning that recommends using createReadStream instead. It will be removed in a future release. Via #107.
  • An Upload scalar variable can now be used by multiple resolvers, via #92.
  • Multiple Upload scalar variables can now use the same multipart data, via #92.
  • Malformed requests containing invalid JSON for operations or map multipart fields cause an appropriate error with a 400 status instead of crashing the process, relating to #81 and #95.
  • Malformed requests missing operations, map and files, or just map and files, cause an appropriate error with a 400 status instead of hanging, fixing #96.
  • Tweaked GraphQLUpload scalar description to remove details about how it resolves on the server as they are irrelevant to API users.
  • Tweaked GraphQLUpload scalar error messages.

Patch

  • Updated dev dependencies.
  • Removed the npm-run-all dev dependency and made scripts and tests sync for easier debugging, at the cost of slightly longer build times.
  • Explicitly set processRequest default options instead of relying on busboy defaults.
  • Better organized project file structure.
  • Configured Prettier to lint .yml files.
  • Ensure the readme Travis build status badge only tracks master branch.

6.0.0-alpha.1

Big thanks to new collaborator @mike-marcacci for his help solving tricky bugs and edge-cases!

Major

Minor

  • Refactored package scripts to use prepare to support installation via Git (e.g. npm install jaydenseric/apollo-upload-server).

Patch

  • Updated dependencies.
  • Use single instead of double typographic quotes in error messages.
  • Use babel.config.js instead of .babelrc.js.
  • Enabled shippedProposals in @babel/preset-env config.
  • Improved testing:
    • Use tap instead of ava. Tests no longer transpile on the fly, are faster and AVA no longer dictates the Babel version.
    • Tests run against the actual dist .mjs and .js files in native ESM (--experimental-modules) and CJS environments.
    • Removed get-port dev dependency.
    • Added Express tests.
    • Test middleware error response status codes.
    • Test behavior of aborted HTTP requests.
    • Test that the app can respond if an upload is not handled.
    • Test files to upload are created in context, rather than using arbitrary project files, via #89.
  • Improved package.json scripts:
    • Leveraged npm-run-all more for parallelism and reduced noise.
    • Removed the clean script rimraf dev dependency in favour of native rm -rf. Leaner and faster; we only support *nix now for contributing anyway.
    • No longer use cross-env; contributors with Windows may setup and use a Bash shell.
    • Renamed the ESM environment variable to BABEL_ESM to be more specific.
    • Removed linting fix scripts.
    • Linting included in the test script; Travis CI will fail PR's with lint errors.
    • Custom watch script.
  • Improved ESLint config:
    • Simplified ESLint config with eslint-config-env.
    • Removed redundant eslint-plugin-ava dev dependency and config.
    • Undo overriding ESLint ignoring dotfiles by default as there are none now.
  • Use .prettierignore to leave package.json formatting to npm.
  • Tweaked package description and keywords.
  • Compact package repository field.
  • Improved documentation.
  • Readme badge changes to deal with shields.io unreliability:
    • Use the official Travis build status badge.
    • Use Badgen for the npm version badge.
    • Removed the licence badge. The licence can be found in package.json and rarely changes.
    • Removed the Github issues and stars badges. The readme is most viewed on Github anyway.
  • Changelog version entries now have “Major”, “Minor” and “Patch” subheadings.

5.0.0

Major

  • graphql peer dependency range updated to ^0.13.1 for native ESM support via .mjs. It’s a breaking change despite being a semver patch.

Patch

  • Updated dependencies.
  • More robust npm scripts, with the ability to watch builds and tests together.
  • Fixed missing dev dependency for fetching in tests.
  • Use eslint-plugin-ava.
  • HTTPS package.json author URL.
  • New readme logo URL that doesn’t need to be updated every version.

4.0.2

Patch

  • Temporary solution for importing CommonJS in .mjs, fixing reopened #40.

4.0.1

Patch

  • Correct imports for vanilla Node.js --experimental-modules and .mjs support, fixing #40.

4.0.0

Patch

  • Updated dependencies.
  • Simplified npm scripts.
  • Readme updates:
    • Documented Blob types, via #39.
    • Explained how to use processRequest for custom middleware.
    • Improved usage instructions.
    • Display oldest supported Node.js version.
    • Misc. tweaks including a simpler heading structure.

4.0.0-alpha.3

Minor

Patch

  • Updated dependencies.

4.0.0-alpha.2

Minor

  • Transpile and polyfill for Node.js v6.10+ (down from v7.6+) to support AWS Lambda, fixing #33.
  • Modular project structure that works better for native ESM.
  • Added tests.
  • Set up Travis to test using the latest stable Node.js version and the oldest supported in package.json engines (v6.10).
  • Added a Travis readme badge.
  • Improved error handling, fixing #26:
    • Custom errors are thrown or emitted with meaningful messages that are exported so consumers can use instanceof with them.
    • Where it makes sense, errors cause relevant HTTP status codes to be set in middleware.
    • Misordered multipart fields cause processRequest to throw MapBeforeOperationsUploadError and FilesBeforeMapUploadError errors in middleware.
    • The map field provided by the client is used to naively check the maxFiles option is not exceeded for a speedy MaxFilesUploadError error in middleware. The real number of files parsed is checked too, incase the request is malformed.
    • If files are missing from the request the scalar Upload promises reject with a FileMissingUploadError error.
    • Already if a file exceeds the maxFileSize option the file is truncated, the stream emits a limit event and stream.truncated === true. Now an error event is also emitted with a MaxFileSizeUploadError.
    • Aborting requests from the client causes scalar Upload promises to reject with a UploadPromiseDisconnectUploadError error for file upload streams that have not yet been parsed. For streams being parsed an error event is emitted with an FileStreamDisconnectUploadError error and stream.truncated === true. It is up to consumers to cleanup aborted streams in their resolvers.

Patch

  • Updated dependencies.
  • Smarter Babel config with .babelrc.js.
  • Refactor to use fewer Busboy event listeners.

4.0.0-alpha.1

Major

  • New API to support the GraphQL multipart request spec v2.0.0-alpha.2. Files no longer upload to the filesystem; readable streams are used in resolvers instead. Fixes #13 via #22.
  • Export a new Upload scalar type to use in place of the old Upload input type. It represents a file upload promise that resolves an object containing stream, filename, mimetype and encoding.
  • Deprecated the uploadDir middleware option.
  • graphql is now a peer dependency.

Minor

  • Added new maxFieldSize, maxFileSize and maxFiles middleware options.

Patch

  • Middleware are now arrow functions.

3.0.0

Major

  • Updated Node.js support from v6.4+ to v7.6+.
  • Express middleware now passes on errors instead of blocking, via #20.

Patch

  • Using Babel directly, dropping Rollup.
  • New directory structure for compiled files.
  • Module files now have .mjs extension.
  • No longer publish the src directory.
  • No more sourcemaps.
  • Use an arrow function for the Koa middleware, to match the Express middleware.
  • Compiled code is now prettier.
  • Prettier markdown files.
  • Updated package keywords.
  • Updated an Apollo documentation link in the changelog.
  • Readme improvements:
    • Added links to badges.
    • Removed the inspiration links; they are less relevant to the evolved codebase.
    • Fixed an Apollo link.
    • Replaced example resolver code with a link to the Apollo upload examples.

2.0.4

Patch

  • Updated dependencies.
  • Readme tweaks including a new license badge.

2.0.3

Patch

  • Updated dependencies.
  • Removed package-lock.json. Lockfiles are not recommended for packages.
  • Moved Babel config out of package.json to prevent issues when consumers run Babel over node_modules.
  • Readme tweaks and fixes:
    • Renamed the File input type Upload for clarity.
    • Wording and formatting improvements.
    • Covered React Native.
    • Documented custom middleware.

2.0.2

Patch

  • Updated dependencies.
  • Added a changelog.
  • Dropped Yarn in favor of npm@5. Removed yarn.lock and updated install instructions.
  • Set targeted Node version as a string for babel-preset-env.
  • New ESLint config. Dropped Standard Style and began using Prettier.
  • Using lint-staged to ensure contributors don't commit lint errors.
  • Removed build:watch script. Use npm run build -- --watch directly.

2.0.1

Patch

  • Updated dependencies.
  • Support regular requests from clients other than apollo-upload-client again, fixing #4.
  • Removed incorrect commas from example GraphQL input type.

2.0.0

Major

Patch

  • Clearer package description.
  • Use Standard Style instead of ESLint directly.

1.1.0

Minor

  • Exporting a new helper function for processing requests. It can be used to create custom middleware, or middleware for unsupported routers.
  • Exporting new Koa middleware.
  • Upload directory is ensured on every request now. While slightly less efficient, it prevents major errors when if it is deleted while the server is running.

Patch

  • Updated dependencies.
  • Documented npm install as well as Yarn.
  • Typo fix in the readme.

1.0.2

Patch

  • Fixed broken Github deep links in the readme.
  • Readme rewording.
  • Simplified package.json description.

1.0.1

Patch

  • Added missing metadata to package.json.
  • Added a link to apollographql/graphql-server in the readme.

1.0.0

Initial release.