1 | # apollo-fetch-upload
|
2 |
|
3 | [![npm version](https://img.shields.io/npm/v/apollo-fetch-upload.svg)](https://www.npmjs.com/package/apollo-fetch-upload)
|
4 |
|
5 | Enables the use of [`File`](https://developer.mozilla.org/en/docs/Web/API/File), [`FileList`](https://developer.mozilla.org/en/docs/Web/API/FileList) and [`ReactNativeFile`](#react-native) instances anywhere within mutation or query input variables. With the [`apollo-upload-server`](https://github.com/jaydenseric/apollo-upload-server) middleware setup on the GraphQL server, files upload to a configurable temp directory. `Upload` input type metadata replaces the original files in the arguments received by the resolver.
|
6 |
|
7 | Checkout the [example API and client](https://github.com/jaydenseric/apollo-upload-examples).
|
8 |
|
9 | Use [`apollo-upload-client`](https://github.com/jaydenseric/apollo-upload-client) for earlier versions of [`apollo-client`](https://github.com/apollographql/apollo-client) that do not support an [`apollo-fetch`](https://github.com/apollographql/apollo-fetch) network interface.
|
10 |
|
11 | ## Setup
|
12 |
|
13 | Install with [npm](https://www.npmjs.com):
|
14 |
|
15 | ```
|
16 | npm install apollo-fetch-upload
|
17 | ```
|
18 |
|
19 | To setup an [`ApolloClient`](http://dev.apollodata.com/core/apollo-client-api.html#apollo-client) network interface:
|
20 |
|
21 | ```js
|
22 | import ApolloClient from 'apollo-client'
|
23 | import { createApolloFetchUpload } from 'apollo-fetch-upload'
|
24 | import { print } from 'graphql/language/printer'
|
25 |
|
26 | const apolloFetchUpload = createApolloFetchUpload({
|
27 | uri: 'https://api.githunt.com/graphql'
|
28 | })
|
29 |
|
30 | const ApolloClient = new ApolloClient({
|
31 | networkInterface: {
|
32 | query: request => apolloFetchUpload({
|
33 | ...request,
|
34 | query: print(request.query)
|
35 | })
|
36 | }
|
37 | })
|
38 | ```
|
39 |
|
40 | Alternatively use query batching:
|
41 |
|
42 | ```js
|
43 | import ApolloClient from 'apollo-client'
|
44 | import BatchHttpLink from 'apollo-link-batch-http'
|
45 | import { createApolloFetchUpload } from 'apollo-fetch-upload'
|
46 |
|
47 | const ApolloClient = new ApolloClient({
|
48 | networkInterface: new BatchHttpLink({
|
49 | fetch: createApolloFetchUpload({
|
50 | uri: 'https://api.githunt.com/graphql'
|
51 | })
|
52 | })
|
53 | })
|
54 | ```
|
55 |
|
56 | `createApolloFetchUpload` and `constructUploadOptions` have the same [API](https://github.com/apollographql/apollo-fetch#api) as `createApolloFetch` and `constructDefaultOptions` in [`apollo-fetch`](https://github.com/apollographql/apollo-fetch).
|
57 |
|
58 | See also the [setup instructions](https://github.com/jaydenseric/apollo-upload-server#setup) for the [`apollo-upload-server`](https://github.com/jaydenseric/apollo-upload-server) middleware.
|
59 |
|
60 | ## Usage
|
61 |
|
62 | Use [`File`](https://developer.mozilla.org/en/docs/Web/API/File), [`FileList`](https://developer.mozilla.org/en/docs/Web/API/FileList) or [`ReactNativeFile`](#react-native) instances anywhere within mutation or query input variables. For server instructions see [`apollo-upload-server`](https://github.com/jaydenseric/apollo-upload-server). Checkout the [example API and client](https://github.com/jaydenseric/apollo-upload-examples).
|
63 |
|
64 | ### [`File`](https://developer.mozilla.org/en/docs/Web/API/File) example
|
65 |
|
66 | ```jsx
|
67 | import { graphql, gql } from 'react-apollo'
|
68 |
|
69 | const UploadFile = ({ mutate }) => {
|
70 | const handleChange = ({ target }) =>
|
71 | target.validity.valid &&
|
72 | mutate({
|
73 | variables: {
|
74 | file: target.files[0]
|
75 | }
|
76 | })
|
77 |
|
78 | return <input type="file" required onChange={handleChange} />
|
79 | }
|
80 |
|
81 | export default graphql(gql`
|
82 | mutation($file: Upload!) {
|
83 | uploadFile(file: $file) {
|
84 | id
|
85 | }
|
86 | }
|
87 | `)(UploadFile)
|
88 | ```
|
89 |
|
90 | ### [`FileList`](https://developer.mozilla.org/en/docs/Web/API/FileList) example
|
91 |
|
92 | ```jsx
|
93 | import { graphql, gql } from 'react-apollo'
|
94 |
|
95 | const UploadFiles = ({ mutate }) => {
|
96 | const handleChange = ({ target }) =>
|
97 | target.validity.valid &&
|
98 | mutate({
|
99 | variables: {
|
100 | files: target.files
|
101 | }
|
102 | })
|
103 |
|
104 | return <input type="file" multiple required onChange={handleChange} />
|
105 | }
|
106 |
|
107 | export default graphql(gql`
|
108 | mutation($files: [Upload!]!) {
|
109 | uploadFiles(files: $files) {
|
110 | id
|
111 | }
|
112 | }
|
113 | `)(UploadFiles)
|
114 | ```
|
115 |
|
116 | ### React Native
|
117 |
|
118 | Substitute [`File`](https://developer.mozilla.org/en/docs/Web/API/File) with `ReactNativeFile` from [`extract-files`](https://github.com/jaydenseric/extract-files):
|
119 |
|
120 | ```js
|
121 | import { ReactNativeFile } from 'apollo-fetch-upload'
|
122 |
|
123 | const variables = {
|
124 | file: new ReactNativeFile({
|
125 | uri: /* Camera roll URI */,
|
126 | type: 'image/jpeg',
|
127 | name: 'photo.jpg'
|
128 | }),
|
129 | files: ReactNativeFile.list([{
|
130 | uri: /* Camera roll URI */,
|
131 | type: 'image/jpeg',
|
132 | name: 'photo-1.jpg'
|
133 | }, {
|
134 | uri: /* Camera roll URI */,
|
135 | type: 'image/jpeg',
|
136 | name: 'photo-2.jpg'
|
137 | }])
|
138 | }
|
139 | ```
|
140 |
|
141 | ## How it works
|
142 |
|
143 | An ‘operations object’ is a [GraphQL request](http://dev.apollodata.com/tools/graphql-server/requests.html#postRequests) (or array of requests if batching). A ‘file’ is a [`File`](https://developer.mozilla.org/en/docs/Web/API/File) or [`ReactNativeFile`](#react-native) instance.
|
144 |
|
145 | When an operations object is to be sent to the GraphQL server, any files within are extracted using [`extract-files`](https://github.com/jaydenseric/extract-files), remembering their object paths within request variables.
|
146 |
|
147 | If no files are extracted a normal fetch with default options happens; the operations object is converted to JSON and sent in the fetch body.
|
148 |
|
149 | Files must upload as individual multipart form fields. A new [`FormData`](https://developer.mozilla.org/en/docs/Web/API/FormData) form is created and each extracted file is appended as a field named after the file's original operations object path; for example `variables.files.0` or `0.variables.files.0` if batching. The operations object (now without files) is converted to JSON and appended as a field named `operations`. The form is sent in the fetch body.
|
150 |
|
151 | Multipart GraphQL server requests are handled by [`apollo-upload-server`](https://github.com/jaydenseric/apollo-upload-server) middleware. The files upload to a temp directory, the `operations` field is JSON decoded and [`object-path`](https://github.com/mariocasciaro/object-path) is used to insert metadata about each of the uploads (including the temp path) in place of the original files in the resolver arguments.
|