Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A spec for GraphQL multipart form requests (file uploads).

NotificationsYou must be signed in to change notification settings

jaydenseric/graphql-multipart-request-spec

Repository files navigation

An interoperablemultipart form field structure for GraphQL requests, used by various file upload client/server implementations.

It’s possible to implement:

  • Nesting files anywhere within operations (usually invariables).
  • Operation batching.
  • File deduplication.
  • File upload streams in resolvers.
  • Aborting file uploads in resolvers.

Sync vs async GraphQL multipart request middleware

Multipart form field structure

An “operations object” is anApollo GraphQL POST request (or array of requests if batching). An “operations path” is anobject-path string to locate a file within an operations object.

So operations can be resolved while the files are still uploading, the fields are ordered:

  1. operations: A JSON encoded operations object with files replaced withnull.
  2. map: A JSON encoded map of where files occurred in the operations. For each file, the key is the file multipart form field name and the value is an array of operations paths.
  3. File fields: Each file extracted from the operations object with a unique, arbitrary field name.

Examples

Single file

Operations

{query:`    mutation($file: Upload!) {      singleUpload(file: $file) {        id      }    }  `,variables:{file:File// a.txt}}

cURL request

curl localhost:3001/graphql \  -F operations='{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { id } }", "variables": { "file": null } }' \  -F map='{ "0": ["variables.file"] }' \  -F 0=@a.txt

Request payload

--------------------------cec8e8123c05ba25Content-Disposition: form-data; name="operations"{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { id } }", "variables": { "file": null } }--------------------------cec8e8123c05ba25Content-Disposition: form-data; name="map"{ "0": ["variables.file"] }--------------------------cec8e8123c05ba25Content-Disposition: form-data; name="0"; filename="a.txt"Content-Type: text/plainAlpha file content.--------------------------cec8e8123c05ba25--

File list

Operations

{query:`    mutation($files: [Upload!]!) {      multipleUpload(files: $files) {        id      }    }  `,variables:{files:[File,// b.txtFile// c.txt]}}

cURL request

curl localhost:3001/graphql \  -F operations='{ "query": "mutation($files: [Upload!]!) { multipleUpload(files: $files) { id } }", "variables": { "files": [null, null] } }' \  -F map='{ "0": ["variables.files.0"], "1": ["variables.files.1"] }' \  -F 0=@b.txt \  -F 1=@c.txt

Request payload

--------------------------ec62457de6331cadContent-Disposition: form-data; name="operations"{ "query": "mutation($files: [Upload!]!) { multipleUpload(files: $files) { id } }", "variables": { "files": [null, null] } }--------------------------ec62457de6331cadContent-Disposition: form-data; name="map"{ "0": ["variables.files.0"], "1": ["variables.files.1"] }--------------------------ec62457de6331cadContent-Disposition: form-data; name="0"; filename="b.txt"Content-Type: text/plainBravo file content.--------------------------ec62457de6331cadContent-Disposition: form-data; name="1"; filename="c.txt"Content-Type: text/plainCharlie file content.--------------------------ec62457de6331cad--

Batching

Operations

[{query:`      mutation($file: Upload!) {        singleUpload(file: $file) {          id        }      }    `,variables:{file:File,// a.txt},},{query:`      mutation($files: [Upload!]!) {        multipleUpload(files: $files) {          id        }      }    `,variables:{files:[File,// b.txtFile,// c.txt],},},];

cURL request

curl localhost:3001/graphql \  -F operations='[{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { id } }", "variables": { "file": null } }, { "query": "mutation($files: [Upload!]!) { multipleUpload(files: $files) { id } }", "variables": { "files": [null, null] } }]' \  -F map='{ "0": ["0.variables.file"], "1": ["1.variables.files.0"], "2": ["1.variables.files.1"] }' \  -F 0=@a.txt \  -F 1=@b.txt \  -F 2=@c.txt

Request payload

--------------------------627436eaefdbc285Content-Disposition: form-data; name="operations"[{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { id } }", "variables": { "file": null } }, { "query": "mutation($files: [Upload!]!) { multipleUpload(files: $files) { id } }", "variables": { "files": [null, null] } }]--------------------------627436eaefdbc285Content-Disposition: form-data; name="map"{ "0": ["0.variables.file"], "1": ["1.variables.files.0"], "2": ["1.variables.files.1"] }--------------------------627436eaefdbc285Content-Disposition: form-data; name="0"; filename="a.txt"Content-Type: text/plainAlpha file content.--------------------------627436eaefdbc285Content-Disposition: form-data; name="1"; filename="b.txt"Content-Type: text/plainBravo file content.--------------------------627436eaefdbc285Content-Disposition: form-data; name="2"; filename="c.txt"Content-Type: text/plainCharlie file content.--------------------------627436eaefdbc285--

Security

GraphQL server authentication and security mechanisms are beyond the scope of this specification, which only covers a multipart form field structure for GraphQL requests.

Note that a GraphQL multipart request has theContent-Typemultipart/form-data; if a browser making such a request determines it meets the criteria for a “simple request” as defined in theFetch specification for theCross-Origin Resource Sharing (CORS) protocol, it won’t cause aCORS preflight request. GraphQL server authentication and security mechanisms must consider this to preventCross-Site Request Forgery (CSRF) attacks.

Implementations

Pull requests adding either experimental or mature implementations to these lists are welcome!Strikethrough means the project was renamed, deprecated, or no longer supports this spec out of the box (but might via an optional integration).

Client

Server

About

A spec for GraphQL multipart form requests (file uploads).

Topics

Resources

Stars

Watchers

Forks

Sponsor this project

 

[8]ページ先頭

©2009-2025 Movatter.jp