0.1.1 • Published 5 years ago

gql-multipart v0.1.1

Weekly downloads
1
License
MIT
Repository
github
Last release
5 years ago

gql-multipart

NPM Version NPM Downloads Build Status Test Coverage Dependencies DevDependencies

NPM

Complementary middleware for express-graphql and koa-graphql which adds support parsing multipart request and file uploads.

Installation

$ npm install gql-multipart

API

gqlMultipartExpress()

This method creates middleware for Express library

gqlMultipartExpress([options: GQLMultipartOptions])

gqlMultipartKoa()

This method creates middleware for Koa library

gqlMultipartKoa([options: GQLMultipartOptions])

GQLMultipartOptions

  • highWaterMark - integer: highWaterMark to use for multipart parser instance (Default: WritableStream default).
  • fileHwm - integer: highWaterMark to use for temp file streams (Default: ReadableStream default).
  • defCharset - string: Default character set to use when one isn't defined (Default: 'utf8').
  • tempDir - string: Determines temp directory. Default OS temp directory.
  • maxFieldNameSize - integer: Max field name size (in bytes) (Default: 100 bytes).
  • maxFieldSize - integer: Max field value size (in bytes) (Default: 1MB).
  • maxFields - integer: Max number of non-file fields (Default: Infinity).
  • maxFileSize - integer: The max file size (in bytes) (Default: Infinity).
  • maxFiles - integer: The max number of file fields (Default: Infinity).
  • maxHeaderPairs - integer: The max number of header key=>value pairs to parse Default: 2000 (same as node's http).

Setup

Just mount express-graphql as a route handler before any graphql handler middleware.

Setup for Express

GraphQL schema used in following examples:

import {buildSchema} from "graphql";

const schema = buildSchema(`
   scalar File
  
    type User {
      id: Int
      name: String
      email: String
    }
    
    type Query {    
      user(id: Int!): User
    }
    
    type Mutation {
      createUser(name: String, email: String): User
      uploadFile(userId: Int!, file: File!): String    
      uploadFiles(userId: Int!, files: [File!]!): [String]
    }
  
`);

const resolvers = {

   user: (args) => {
         // return user instance
       },
   
       uploadFile: ({file}) => {
         // do anything with file
         const data = fs.readFileSync(file.tempFile, file.encoding);    
         return 'OK'
       },
   
       uploadFiles: ({files}) => {        
           for (const f of files) {
             // do anything with file
             const data = fs.readFileSync(f.tempFile, f.encoding);            
           }
           return 'OK';
       }

};

module.exports = {schema, resolvers};
import express from "express";
import graphqlHTTP from "express-graphql";
import {gqlMultipartExpress} from "gql-multipart";
import {schema, resolvers} from "./my-schema";

const app = express();
app.use('/graphql', gqlMultipartExpress()); // Must be mounted before express-graphql
app.use('/graphql', graphqlHTTP({
    schema: this.schema,
    rootValue: resolvers
}));

Setup for Koa

import Koa from "Koa";
import mount from "koa-mount";
import {gqlMultipartKoa} from "gql-multipart";
import {schema, resolvers} from "./my-schema";

const app = new Koa();
app.use(mount('/graphql', gqlMultipartKoa()));  // Must be mounted before koa-graphql
app.use(mount('/graphql', graphqlHTTP({
    schema: this.schema,
    rootValue: resolvers
})));

Client implementation

Request can be send easily using any client implementation which supports multipart form data.

SPEC

Consider the following guidelines:

  1. First part must contain graphql payload data as JSON encoded string and part name must be "payload"

  2. Following parts must contain variables and names must start with "$" character.

  3. Non string variables (number, boolean, array, object) must be encoded as JSON and Content-Type must be application/json.

  4. To send array of file for single variable, use same part name.

Simple client using fetch

gql-multipart spec is very simple and you do not need any client implementations. Following example uses FormData and fetch() method.

function uploadFile(ownerId, ownerName, file, encoding) {
  const form = new FormData();
  const payload = {
      query: `
          mutation ($userId: Int!, $file: File!) {
            uploadFile(userId: $userId, file: $file)           
          }`
  };
  form.append('payload', JSON.stringify(payload));
  form.append('$userId', ownerId, {
      header: {'content-type': 'application/json'}
  }); 
  form.append('$file', file, {
      header: encoding ? {'content-transfer-encoding': encoding}: null
  });
  
  return fetch('http://localhost:3999/graphql', {
      method: 'POST',
      body: form
  }).then((res) => {
      // Upload complete
  });
}
function uploadFiles(ownerId, ownerName, files) {
  const form = new FormData();
  const payload = {
      query: `
          mutation ($userId: Int!, $files: [File!]!) {
            uploadFiles(userId: $userId, files: $files)           
          }`
  };
  form.append('payload', JSON.stringify(payload));
  form.append('$userId', ownerId, {
      header: {'content-type': 'application/json'}
  }); 
  for (const f of files) {
    form.append('$files', f);
  }
  
  return fetch('http://localhost:3999/graphql', {
      method: 'POST',
      body: form
  }).then((res) => {
      // Upload complete
  });
}

Sample request body

--------------------------5743007ba5b4
Content-Disposition: form-data; name="payload"

{ "query": "mutation ($userId: Int!, $file: File!) { uploadFile(userId: $userId, file: $file) }" }
--------------------------5743007ba5b4
Content-Disposition: form-data; name="$userId"
Content-Type: application/json

1528
--------------------------5743007ba5b4
Content-Disposition: form-data; name="$file"; filename="anyfile.txt"
Content-Type: text/plain

Any file content.

--------------------------5743007ba5b4--

Known client implementations

Compatibility

  • node with Express >= 6.x;
  • node with Koa >= 8.x;

License

MIT

0.1.1

5 years ago

0.1.0

5 years ago

0.0.11

5 years ago

0.0.10

5 years ago

0.0.9

5 years ago

0.0.8

5 years ago

0.0.7

5 years ago

0.0.6

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago