/apollo-upload-server

Enhances Apollo for intuitive file uploads via GraphQL mutations.

Primary LanguageJavaScript

Apollo upload server

NPM version Github issues Github stars

Enhances Apollo for intuitive file uploads via GraphQL mutations or queries. Use with Apollo upload client.

Setup

Install

With NPM:

npm install apollo-upload-server --save

With Yarn:

yarn add apollo-upload-server

Server middleware

Add the server middleware just before graphql-server.

For Express:

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

// ✂

app.use(
  '/graphql',
  bodyParser.json(),
  apolloUploadExpress({
    // Optional, defaults to OS temp directory
    uploadDir: '/tmp/uploads'
  }),
  graphqlExpress(/* ✂ */)
)

// ✂

For Koa:

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

// ✂

router.post(
  '/graphql',
  apolloUploadKoa({
    // Optional, defaults to OS temp directory
    uploadDir: '/tmp/uploads'
  }),
  graphqlKoa(/* ✂ */)
)

// ✂

Types

Add an input type to your schema. You can name it anything but it must have this shape:

input File {
  name: String!
  type: String!
  size: Int!
  path: String!
}

Client

Also setup Apollo upload client.

Usage

Once setup, you will be able to use File objects, FileList objects, or File arrays within query or mutation input variables. See the client usage.

The files upload to a temp directory. The file path and metadata will be available under the variable name in the resolver in the shape of the input File type in the GraphQL schema.

The resolver variable will hold an array if it is populated as a list (FileList or File array) on the client – even if the list has only 1 file.

Single file

In types:

type Mutation {
  updateUserAvatar (userId: String!, avatar: File!): User!
}

In resolvers:

updateUserAvatar (root, {userId, avatar}) {
  // Auth…
  // Update avatar…
  console.log(`New avatar for user ${userId} is ${avatar.size} bytes`)
  // Return fresh user data…
}

See client usage for this example.

Multiple files

In types:

type Mutation {
  updateGallery (galleryId: String!, images: [File!]!): Gallery!
}

In resolvers:

updateGallery (root, {galleryId, images}) {
  // Auth…
  // Update gallery…
  console.log(`New images for gallery ${userId}:`)
  images.forEach((image, index) => console.log(`Image ${index} is ${image.size} bytes`))
  // Return fresh gallery data…
}

See client usage for this example.

Caveats

  • No max upload file size option yet.

Inspiration