apollo-upload-client
Advanced tools
Comparing version 2.0.2 to 3.0.0
@@ -11,2 +11,67 @@ 'use strict'; | ||
/** | ||
* Extracts files from an Apollo Client Request, remembering positions in variables. | ||
* @see {@link http://dev.apollodata.com/core/apollo-client-api.html#Request} | ||
* @param {Object} request - Apollo GraphQL request to be sent to the server. | ||
* @param {Object} request.variables - GraphQL variables map. | ||
* @param {string} request.operationName - Name of the GraphQL query or mutation. | ||
* @returns {Object} - Request with files extracted to a list with their original object paths. | ||
*/ | ||
function extractRequestFiles(request) { | ||
var files = []; | ||
var variablesPath = void 0; | ||
// Recursively search GraphQL input variables for FileList or File objects | ||
for (var _iterator = new RecursiveIterator(request.variables), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref2; | ||
if (_isArray) { | ||
if (_i >= _iterator.length) break; | ||
_ref2 = _iterator[_i++]; | ||
} else { | ||
_i = _iterator.next(); | ||
if (_i.done) break; | ||
_ref2 = _i.value; | ||
} | ||
var _ref = _ref2; | ||
var node = _ref.node, | ||
path = _ref.path; | ||
var isFileList = node instanceof window.FileList; | ||
var isFile = node instanceof window.File; | ||
if (isFileList || isFile) { | ||
// Only populate when necessary | ||
if (!variablesPath) variablesPath = objectPath(request.variables); | ||
var pathString = path.join('.'); | ||
if (isFileList) { | ||
// Convert to FileList to File array. This is | ||
// necessary so items can be manipulated correctly | ||
// by object-path. Either format may be used when | ||
// populating GraphQL variables on the client. | ||
variablesPath.set(pathString, Array.from(node)); | ||
} else if (isFile) { | ||
// Move the File object to a multipart form field | ||
// with the field name holding the original path | ||
// to the file in the GraphQL input variables. | ||
files.push({ | ||
variablesPath: 'variables.' + pathString, | ||
file: node | ||
}); | ||
variablesPath.del(pathString); | ||
} | ||
} | ||
} | ||
request.query = apolloClient.printAST(request.query); | ||
return { | ||
operation: request, | ||
files: files | ||
}; | ||
} | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
@@ -35,86 +100,89 @@ | ||
var hasFile = false; | ||
var variables = void 0; | ||
var formData = void 0; | ||
var formData = new window.FormData(); | ||
// Recursively search GraphQL input variables for FileList or File objects | ||
for (var _iterator = new RecursiveIterator(request.variables), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref3; | ||
var _extractRequestFiles = extractRequestFiles(request), | ||
operation = _extractRequestFiles.operation, | ||
files = _extractRequestFiles.files; | ||
if (_isArray) { | ||
if (_i >= _iterator.length) break; | ||
_ref3 = _iterator[_i++]; | ||
} else { | ||
_i = _iterator.next(); | ||
if (_i.done) break; | ||
_ref3 = _i.value; | ||
} | ||
formData.append('operations', JSON.stringify(operation)); | ||
files.forEach(function (_ref2) { | ||
var variablesPath = _ref2.variablesPath, | ||
file = _ref2.file; | ||
return formData.append(variablesPath, file); | ||
}); | ||
return window.fetch(this._uri, _extends({ | ||
method: 'POST', | ||
body: formData | ||
}, options)); | ||
}; | ||
var _ref2 = _ref3; | ||
var node = _ref2.node, | ||
path = _ref2.path; | ||
return HTTPUploadNetworkInterface; | ||
}(apolloClient.HTTPFetchNetworkInterface); | ||
var isFileList = node instanceof window.FileList; | ||
var isFile = node instanceof window.File; | ||
function createNetworkInterface(_ref3) { | ||
var uri = _ref3.uri, | ||
options = _objectWithoutProperties(_ref3, ['uri']); | ||
// Only populate certain variables when nessesary | ||
if (isFileList || isFile) { | ||
if (!variables) variables = objectPath(request.variables); | ||
var pathString = path.join('.'); | ||
} | ||
return new HTTPUploadNetworkInterface(uri, options); | ||
} | ||
if (isFileList) { | ||
// Convert to FileList to File array. This is | ||
// nessesary so items can be manipulated correctly | ||
// by object-path. Either format may be used when | ||
// populating GraphQL variables on the client. | ||
variables.set(pathString, Array.from(node)); | ||
} else if (isFile) { | ||
// Check if this is the first file found | ||
if (!hasFile) { | ||
hasFile = true; | ||
formData = new window.FormData(); | ||
} | ||
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
// Move the File object to a multipart form field | ||
// with the field name holding the original path | ||
// to the file in the GraphQL input variables. | ||
formData.append(pathString, node); | ||
variables.del(pathString); | ||
} | ||
} | ||
function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
if (hasFile) { | ||
// Add Apollo fields to the form | ||
formData.append('operationName', request.operationName); | ||
formData.append('query', apolloClient.printAST(request.query)); | ||
formData.append('variables', JSON.stringify(request.variables)); | ||
function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
// Send the multipart form | ||
return window.fetch(this._uri, _extends({ | ||
body: formData, | ||
method: 'POST' | ||
}, options, { | ||
headers: _extends({ | ||
Accept: '*/*' | ||
}, options.headers) | ||
})); | ||
} else { | ||
// No uploads, use the standard method | ||
return _HTTPFetchNetworkInte.prototype.fetchFromRemoteEndpoint.call(this, { request: request, options: options }); | ||
} | ||
function _possibleConstructorReturn$1(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _inherits$1(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
var HTTPUploadBatchNetworkInterface = function (_HTTPBatchedNetworkIn) { | ||
_inherits$1(HTTPUploadBatchNetworkInterface, _HTTPBatchedNetworkIn); | ||
function HTTPUploadBatchNetworkInterface() { | ||
_classCallCheck$1(this, HTTPUploadBatchNetworkInterface); | ||
return _possibleConstructorReturn$1(this, _HTTPBatchedNetworkIn.apply(this, arguments)); | ||
} | ||
HTTPUploadBatchNetworkInterface.prototype.batchedFetchFromRemoteEndpoint = function batchedFetchFromRemoteEndpoint(_ref) { | ||
var requests = _ref.requests, | ||
options = _ref.options; | ||
var formData = new window.FormData(); | ||
var operations = requests.map(function (request, index) { | ||
var _extractRequestFiles = extractRequestFiles(request), | ||
operation = _extractRequestFiles.operation, | ||
files = _extractRequestFiles.files; | ||
files.forEach(function (_ref2) { | ||
var variablesPath = _ref2.variablesPath, | ||
file = _ref2.file; | ||
return formData.append(index + '.' + variablesPath, file); | ||
}); | ||
return operation; | ||
}); | ||
formData.append('operations', JSON.stringify(operations)); | ||
return window.fetch(this._uri, _extends$1({ | ||
method: 'POST', | ||
body: formData | ||
}, options)); | ||
}; | ||
return HTTPUploadNetworkInterface; | ||
}(apolloClient.HTTPFetchNetworkInterface); | ||
return HTTPUploadBatchNetworkInterface; | ||
}(apolloClient.HTTPBatchedNetworkInterface); | ||
function createNetworkInterface(_ref4) { | ||
var uri = _ref4.uri, | ||
options = _objectWithoutProperties(_ref4, ['uri']); | ||
function createBatchNetworkInterface(_ref3) { | ||
var uri = _ref3.uri, | ||
batchInterval = _ref3.batchInterval, | ||
options = _objectWithoutProperties$1(_ref3, ['uri', 'batchInterval']); | ||
return new HTTPUploadNetworkInterface(uri, options); | ||
return new HTTPUploadBatchNetworkInterface(uri, batchInterval, options); | ||
} | ||
exports.extractRequestFiles = extractRequestFiles; | ||
exports.HTTPUploadNetworkInterface = HTTPUploadNetworkInterface; | ||
exports.createNetworkInterface = createNetworkInterface; | ||
exports.HTTPUploadBatchNetworkInterface = HTTPUploadBatchNetworkInterface; | ||
exports.createBatchNetworkInterface = createBatchNetworkInterface; | ||
//# sourceMappingURL=apollo-upload-client.js.map |
@@ -1,5 +0,70 @@ | ||
import { HTTPFetchNetworkInterface, printAST } from 'apollo-client'; | ||
import { HTTPBatchedNetworkInterface, HTTPFetchNetworkInterface, printAST } from 'apollo-client'; | ||
import RecursiveIterator from 'recursive-iterator'; | ||
import objectPath from 'object-path'; | ||
/** | ||
* Extracts files from an Apollo Client Request, remembering positions in variables. | ||
* @see {@link http://dev.apollodata.com/core/apollo-client-api.html#Request} | ||
* @param {Object} request - Apollo GraphQL request to be sent to the server. | ||
* @param {Object} request.variables - GraphQL variables map. | ||
* @param {string} request.operationName - Name of the GraphQL query or mutation. | ||
* @returns {Object} - Request with files extracted to a list with their original object paths. | ||
*/ | ||
function extractRequestFiles(request) { | ||
var files = []; | ||
var variablesPath = void 0; | ||
// Recursively search GraphQL input variables for FileList or File objects | ||
for (var _iterator = new RecursiveIterator(request.variables), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref2; | ||
if (_isArray) { | ||
if (_i >= _iterator.length) break; | ||
_ref2 = _iterator[_i++]; | ||
} else { | ||
_i = _iterator.next(); | ||
if (_i.done) break; | ||
_ref2 = _i.value; | ||
} | ||
var _ref = _ref2; | ||
var node = _ref.node, | ||
path = _ref.path; | ||
var isFileList = node instanceof window.FileList; | ||
var isFile = node instanceof window.File; | ||
if (isFileList || isFile) { | ||
// Only populate when necessary | ||
if (!variablesPath) variablesPath = objectPath(request.variables); | ||
var pathString = path.join('.'); | ||
if (isFileList) { | ||
// Convert to FileList to File array. This is | ||
// necessary so items can be manipulated correctly | ||
// by object-path. Either format may be used when | ||
// populating GraphQL variables on the client. | ||
variablesPath.set(pathString, Array.from(node)); | ||
} else if (isFile) { | ||
// Move the File object to a multipart form field | ||
// with the field name holding the original path | ||
// to the file in the GraphQL input variables. | ||
files.push({ | ||
variablesPath: 'variables.' + pathString, | ||
file: node | ||
}); | ||
variablesPath.del(pathString); | ||
} | ||
} | ||
} | ||
request.query = printAST(request.query); | ||
return { | ||
operation: request, | ||
files: files | ||
}; | ||
} | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
@@ -28,85 +93,85 @@ | ||
var hasFile = false; | ||
var variables = void 0; | ||
var formData = void 0; | ||
var formData = new window.FormData(); | ||
// Recursively search GraphQL input variables for FileList or File objects | ||
for (var _iterator = new RecursiveIterator(request.variables), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref3; | ||
var _extractRequestFiles = extractRequestFiles(request), | ||
operation = _extractRequestFiles.operation, | ||
files = _extractRequestFiles.files; | ||
if (_isArray) { | ||
if (_i >= _iterator.length) break; | ||
_ref3 = _iterator[_i++]; | ||
} else { | ||
_i = _iterator.next(); | ||
if (_i.done) break; | ||
_ref3 = _i.value; | ||
} | ||
formData.append('operations', JSON.stringify(operation)); | ||
files.forEach(function (_ref2) { | ||
var variablesPath = _ref2.variablesPath, | ||
file = _ref2.file; | ||
return formData.append(variablesPath, file); | ||
}); | ||
return window.fetch(this._uri, _extends({ | ||
method: 'POST', | ||
body: formData | ||
}, options)); | ||
}; | ||
var _ref2 = _ref3; | ||
var node = _ref2.node, | ||
path = _ref2.path; | ||
return HTTPUploadNetworkInterface; | ||
}(HTTPFetchNetworkInterface); | ||
var isFileList = node instanceof window.FileList; | ||
var isFile = node instanceof window.File; | ||
function createNetworkInterface(_ref3) { | ||
var uri = _ref3.uri, | ||
options = _objectWithoutProperties(_ref3, ['uri']); | ||
// Only populate certain variables when nessesary | ||
if (isFileList || isFile) { | ||
if (!variables) variables = objectPath(request.variables); | ||
var pathString = path.join('.'); | ||
} | ||
return new HTTPUploadNetworkInterface(uri, options); | ||
} | ||
if (isFileList) { | ||
// Convert to FileList to File array. This is | ||
// nessesary so items can be manipulated correctly | ||
// by object-path. Either format may be used when | ||
// populating GraphQL variables on the client. | ||
variables.set(pathString, Array.from(node)); | ||
} else if (isFile) { | ||
// Check if this is the first file found | ||
if (!hasFile) { | ||
hasFile = true; | ||
formData = new window.FormData(); | ||
} | ||
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
// Move the File object to a multipart form field | ||
// with the field name holding the original path | ||
// to the file in the GraphQL input variables. | ||
formData.append(pathString, node); | ||
variables.del(pathString); | ||
} | ||
} | ||
function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
if (hasFile) { | ||
// Add Apollo fields to the form | ||
formData.append('operationName', request.operationName); | ||
formData.append('query', printAST(request.query)); | ||
formData.append('variables', JSON.stringify(request.variables)); | ||
function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
// Send the multipart form | ||
return window.fetch(this._uri, _extends({ | ||
body: formData, | ||
method: 'POST' | ||
}, options, { | ||
headers: _extends({ | ||
Accept: '*/*' | ||
}, options.headers) | ||
})); | ||
} else { | ||
// No uploads, use the standard method | ||
return _HTTPFetchNetworkInte.prototype.fetchFromRemoteEndpoint.call(this, { request: request, options: options }); | ||
} | ||
function _possibleConstructorReturn$1(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _inherits$1(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
var HTTPUploadBatchNetworkInterface = function (_HTTPBatchedNetworkIn) { | ||
_inherits$1(HTTPUploadBatchNetworkInterface, _HTTPBatchedNetworkIn); | ||
function HTTPUploadBatchNetworkInterface() { | ||
_classCallCheck$1(this, HTTPUploadBatchNetworkInterface); | ||
return _possibleConstructorReturn$1(this, _HTTPBatchedNetworkIn.apply(this, arguments)); | ||
} | ||
HTTPUploadBatchNetworkInterface.prototype.batchedFetchFromRemoteEndpoint = function batchedFetchFromRemoteEndpoint(_ref) { | ||
var requests = _ref.requests, | ||
options = _ref.options; | ||
var formData = new window.FormData(); | ||
var operations = requests.map(function (request, index) { | ||
var _extractRequestFiles = extractRequestFiles(request), | ||
operation = _extractRequestFiles.operation, | ||
files = _extractRequestFiles.files; | ||
files.forEach(function (_ref2) { | ||
var variablesPath = _ref2.variablesPath, | ||
file = _ref2.file; | ||
return formData.append(index + '.' + variablesPath, file); | ||
}); | ||
return operation; | ||
}); | ||
formData.append('operations', JSON.stringify(operations)); | ||
return window.fetch(this._uri, _extends$1({ | ||
method: 'POST', | ||
body: formData | ||
}, options)); | ||
}; | ||
return HTTPUploadNetworkInterface; | ||
}(HTTPFetchNetworkInterface); | ||
return HTTPUploadBatchNetworkInterface; | ||
}(HTTPBatchedNetworkInterface); | ||
function createNetworkInterface(_ref4) { | ||
var uri = _ref4.uri, | ||
options = _objectWithoutProperties(_ref4, ['uri']); | ||
function createBatchNetworkInterface(_ref3) { | ||
var uri = _ref3.uri, | ||
batchInterval = _ref3.batchInterval, | ||
options = _objectWithoutProperties$1(_ref3, ['uri', 'batchInterval']); | ||
return new HTTPUploadNetworkInterface(uri, options); | ||
return new HTTPUploadBatchNetworkInterface(uri, batchInterval, options); | ||
} | ||
export { HTTPUploadNetworkInterface, createNetworkInterface }; | ||
export { extractRequestFiles, HTTPUploadNetworkInterface, createNetworkInterface, HTTPUploadBatchNetworkInterface, createBatchNetworkInterface }; | ||
//# sourceMappingURL=apollo-upload-client.module.js.map |
{ | ||
"name": "apollo-upload-client", | ||
"version": "2.0.2", | ||
"description": "Enhances Apollo for intuitive file uploads via GraphQL mutations.", | ||
"version": "3.0.0", | ||
"description": "Enhances Apollo Client for intuitive file uploads via GraphQL mutations.", | ||
"license": "MIT", | ||
@@ -6,0 +6,0 @@ "author": { |
@@ -1,2 +0,2 @@ | ||
# ![Apollo upload client](https://cdn.rawgit.com/jaydenseric/apollo-upload-client/v2.0.2/apollo-upload-logo.svg) | ||
# ![Apollo upload client](https://cdn.rawgit.com/jaydenseric/apollo-upload-client/v3.0.0/apollo-upload-logo.svg) | ||
@@ -18,3 +18,3 @@ ![NPM version](https://img.shields.io/npm/v/apollo-upload-client.svg?style=flat-square) ![Github issues](https://img.shields.io/github/issues/jaydenseric/apollo-upload-client.svg?style=flat-square) ![Github stars](https://img.shields.io/github/stars/jaydenseric/apollo-upload-client.svg?style=flat-square) | ||
Create the Apollo client with the special network interface: | ||
Setup Apollo client with a special network interface: | ||
@@ -32,2 +32,16 @@ ```js | ||
Alternatively enable [query batching](http://dev.apollodata.com/core/network.html#query-batching): | ||
```js | ||
import ApolloClient from 'apollo-client' | ||
import {createBatchNetworkInterface} from 'apollo-upload-client' | ||
const client = new ApolloClient({ | ||
networkInterface: createBatchNetworkInterface({ | ||
uri: '/graphql', | ||
batchInterval: 10 | ||
}) | ||
}) | ||
``` | ||
Also setup [Apollo upload server](https://github.com/jaydenseric/apollo-upload-server). | ||
@@ -123,6 +137,2 @@ | ||
## Caveats | ||
- Batching is not compatible as only the standard Apollo network interface has been extended yet. | ||
## Inspiration | ||
@@ -129,0 +139,0 @@ |
@@ -1,68 +0,3 @@ | ||
import {HTTPFetchNetworkInterface, printAST} from 'apollo-client' | ||
import RecursiveIterator from 'recursive-iterator' | ||
import objectPath from 'object-path' | ||
export class HTTPUploadNetworkInterface extends HTTPFetchNetworkInterface { | ||
fetchFromRemoteEndpoint ({request, options}) { | ||
let hasFile = false | ||
let variables | ||
let formData | ||
// Recursively search GraphQL input variables for FileList or File objects | ||
for (let {node, path} of new RecursiveIterator(request.variables)) { | ||
const isFileList = node instanceof window.FileList | ||
const isFile = node instanceof window.File | ||
// Only populate certain variables when nessesary | ||
if (isFileList || isFile) { | ||
if (!variables) variables = objectPath(request.variables) | ||
var pathString = path.join('.') | ||
} | ||
if (isFileList) { | ||
// Convert to FileList to File array. This is | ||
// nessesary so items can be manipulated correctly | ||
// by object-path. Either format may be used when | ||
// populating GraphQL variables on the client. | ||
variables.set(pathString, Array.from(node)) | ||
} else if (isFile) { | ||
// Check if this is the first file found | ||
if (!hasFile) { | ||
hasFile = true | ||
formData = new window.FormData() | ||
} | ||
// Move the File object to a multipart form field | ||
// with the field name holding the original path | ||
// to the file in the GraphQL input variables. | ||
formData.append(pathString, node) | ||
variables.del(pathString) | ||
} | ||
} | ||
if (hasFile) { | ||
// Add Apollo fields to the form | ||
formData.append('operationName', request.operationName) | ||
formData.append('query', printAST(request.query)) | ||
formData.append('variables', JSON.stringify(request.variables)) | ||
// Send the multipart form | ||
return window.fetch(this._uri, { | ||
body: formData, | ||
method: 'POST', | ||
...options, | ||
headers: { | ||
Accept: '*/*', | ||
...options.headers | ||
} | ||
}) | ||
} else { | ||
// No uploads, use the standard method | ||
return super.fetchFromRemoteEndpoint({request, options}) | ||
} | ||
} | ||
} | ||
export function createNetworkInterface ({uri, ...options}) { | ||
return new HTTPUploadNetworkInterface(uri, options) | ||
} | ||
export * from './helpers' | ||
export * from './network-interface' | ||
export * from './batch-network-interface' |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
39432
10
371
140
1