diff --git a/README.md b/README.md index 6b87a3c..bf35c58 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,7 @@ import { RelayNetworkLayer } from 'react-relay-network-modern/es'; - **progressMiddleware** - enable onProgress callback for modern browsers with support for Stream API. - `onProgress` - on progress callback function (`function(bytesCurrent: number, bytesTotal: number | null) => void`, total size will be null if size header is not set) - `sizeHeader` - response header with total size of response (default: `Content-Length`, useful when `Transfer-Encoding: chunked` is set) +- **uploadMiddleware** - extracts [`File`](https://developer.mozilla.org/docs/web/api/file), [`Blob`](https://developer.mozilla.org/docs/web/api/blob) and [`ReactNativeFile`](#class-reactnativefile) instances from query variables to be consumed with [graphql-upload](https://github.com/jaydenseric/graphql-upload) ### Standalone package middlewares @@ -154,6 +155,7 @@ import { authMiddleware, cacheMiddleware, progressMiddleware, + uploadMiddleware, } from 'react-relay-network-modern'; const network = new RelayNetworkLayer( @@ -206,6 +208,7 @@ const network = new RelayNetworkLayer( console.log('Downloaded: ' + current + ' B, total: ' + total + ' B'); }, }), + uploadMiddleware(), // example of the custom inline middleware (next) => async (req) => { diff --git a/package.json b/package.json index 04a4e6a..0470dc0 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,9 @@ "url": "https://github.com/relay-tools/react-relay-network-modern/issues" }, "homepage": "https://github.com/relay-tools/react-relay-network-modern#readme", - "dependencies": {}, + "dependencies": { + "extract-files": "^5.0.1" + }, "optionalDependencies": { "@types/relay-runtime": "^5.0.3" }, diff --git a/src/index.d.ts b/src/index.d.ts index 58a5ad7..5067e9e 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -199,6 +199,8 @@ export interface ProgressOpts { export function progressMiddleware(opts?: ProgressOpts): Middleware; +export function uploadMiddleware(): Middleware; + export type MiddlewareRawNextFn = (req: RelayRequestAny) => Promise; export type MiddlewareRaw = { diff --git a/src/index.js b/src/index.js index 986db53..69553ee 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,7 @@ import loggerMiddleware from './middlewares/logger'; import errorMiddleware from './middlewares/error'; import cacheMiddleware from './middlewares/cache'; import progressMiddleware from './middlewares/progress'; +import uploadMiddleware from './middlewares/upload'; import graphqlBatchHTTPWrapper from './express-middleware/graphqlBatchHTTPWrapper'; import RelayNetworkLayerRequest from './RelayRequest'; import RelayNetworkLayerRequestBatch from './RelayRequestBatch'; @@ -33,6 +34,7 @@ export { errorMiddleware, cacheMiddleware, progressMiddleware, + uploadMiddleware, graphqlBatchHTTPWrapper, RRNLError, RRNLRequestError, diff --git a/src/middlewares/upload.js b/src/middlewares/upload.js new file mode 100644 index 0000000..48b117b --- /dev/null +++ b/src/middlewares/upload.js @@ -0,0 +1,46 @@ +/* @flow */ + +import { extractFiles } from 'extract-files'; + +import type { Middleware } from '../definition'; +import RelayRequestBatch from '../RelayRequestBatch'; + +export default function uploadMiddleware(): Middleware { + return (next) => async (req) => { + if (req instanceof RelayRequestBatch) { + throw new Error('RelayRequestBatch is not supported'); + } + + const operations = { + query: req.operation.text, + variables: req.variables, + }; + + const { clone: extractedOperations, files } = extractFiles(operations); + + if (files.size) { + const formData = new FormData(); + + formData.append('operations', JSON.stringify(extractedOperations)); + + const pathMap = {}; + let i = 0; + files.forEach((paths) => { + pathMap[++i] = paths; + }); + formData.append('map', JSON.stringify(pathMap)); + + i = 0; + files.forEach((paths, file) => { + formData.append(++i, file, file.name); + }); + + req.fetchOpts.method = 'POST'; + req.fetchOpts.body = formData; + } + + const res = await next(req); + + return res; + }; +} diff --git a/yarn.lock b/yarn.lock index da11d68..f468b8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3030,6 +3030,11 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +extract-files@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-5.0.1.tgz#c9492a8410be643e260a376f0151361993d5f659" + integrity sha512-qRW6y9eKF0VbCyOoOEtFhzJ3uykAw8GKwQVXyAIqwocyEWW4m+v+evec34RwtUkkxxHh7NKBLJ6AnXM8W4dH5w== + extsprintf@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"