Skip to content

Commit

Permalink
Add additional options for link customization
Browse files Browse the repository at this point in the history
  • Loading branch information
yaacovCR committed Feb 26, 2020
1 parent fe101fa commit 2f2e2b5
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 7 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"@babel/runtime": "^7.5.4",
"apollo-link": "^1.2.12",
"apollo-link-http-common": "^0.2.14",
"extract-files": "^5.0.1"
"extract-files": "^7.0.0"
},
"devDependencies": {
"@babel/cli": "^7.5.0",
Expand Down
29 changes: 29 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ Consider polyfilling:

- [class ReactNativeFile](#class-reactnativefile)
- [function createUploadLink](#function-createuploadlink)
- [function defaultAppendFile](#function-defaultappendfile)
- [type FetchOptions](#type-fetchoptions)
- [type ReactNativeFileSubstitute](#type-reactnativefilesubstitute)

Expand Down Expand Up @@ -156,6 +157,9 @@ Creates a terminating [Apollo Link](https://apollographql.com/docs/link) capable
| :-- | :-- | :-- |
| `options` | object | Options. |
| `options.uri` | string? = /graphql | GraphQL endpoint URI. |
| `options.FormData` | class? | [`FormData`](https://xhr.spec.whatwg.org/#interface-formdata) implementation to use, defaulting to the `FormData` global. |
| `options.appendFile` | Function? | A function responsible for appending a file to an existing FormData object, defaulting to the exported `defaultAppendFile` function. |
| `options.isExtractableFile` | Function? | A function to pass to [`extractFiles`](https://github.com/jaydenseric/extract-files#function-isextractablefile) to customize checking if a value is an extractable file. |
| `options.fetch` | Function? | [`fetch`](https://fetch.spec.whatwg.org) implementation to use, defaulting to the `fetch` global. |
| `options.fetchOptions` | [FetchOptions](#type-fetchoptions)? | `fetch` options; overridden by upload requirements. |
| `options.credentials` | string? | Overrides `options.fetchOptions.credentials`. |
Expand Down Expand Up @@ -186,6 +190,31 @@ _A basic Apollo Client setup._
---

### function defaultAppendFile

Adds a file to an existing multipart request. By default, simply appends the passed file without any special processing. The `name` property of the `file` object is used as the file name.

| Parameter | Type | Description |
| :-------- | :----- | :----------------------------------------------------- |
| `form` | object | FormData object to which to append the specified file. |
| `name` | string | The name under which the file should be appended. |
| `file` | object | The file to be appended. |

**Returns:** void

#### Examples

_Default appendFile function._

> ```js
> i = 0
> files.forEach((paths, file) => {
> defaultAppendFile(form, ++i, file)
> })
> ```
---

### type FetchOptions

GraphQL request `fetch` options.
Expand Down
43 changes: 37 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ const {
createSignalIfSupported,
parseAndCheckHttpResponse
} = require('apollo-link-http-common')
const { extractFiles, ReactNativeFile } = require('extract-files')
const {
extractFiles,
isExtractableFile,
ReactNativeFile
} = require('extract-files')

/**
* A React Native [`File`](https://developer.mozilla.org/docs/web/api/file)
Expand Down Expand Up @@ -74,6 +78,9 @@ exports.ReactNativeFile = ReactNativeFile
* @name createUploadLink
* @param {object} options Options.
* @param {string} [options.uri=/graphql] GraphQL endpoint URI.
* @param {class} [options.FormData] [`FormData`](https://xhr.spec.whatwg.org/#interface-formdata) implementation to use, defaulting to the `FormData` global.
* @param {Function} [options.appendFile] A function responsible for appending a file to an existing FormData object, defaulting to the exported `defaultAppendFile` function.
* @param {Function} [options.isExtractableFile] A function to pass to [`extractFiles`](https://github.com/jaydenseric/extract-files#function-isextractablefile) to customize checking if a value is an extractable file.
* @param {Function} [options.fetch] [`fetch`](https://fetch.spec.whatwg.org) implementation to use, defaulting to the `fetch` global.
* @param {FetchOptions} [options.fetchOptions] `fetch` options; overridden by upload requirements.
* @param {string} [options.credentials] Overrides `options.fetchOptions.credentials`.
Expand All @@ -94,7 +101,10 @@ exports.ReactNativeFile = ReactNativeFile
*/
exports.createUploadLink = ({
uri: fetchUri = '/graphql',
fetch: linkFetch = fetch,
FormData: CustomFormData = FormData,
appendFile: customAppendFile = defaultAppendFile,
isExtractableFile: customIsExtractableFile = isExtractableFile,
fetch: customFetch = fetch,
fetchOptions,
credentials,
headers,
Expand Down Expand Up @@ -139,7 +149,7 @@ exports.createUploadLink = ({
contextConfig
)

const { clone, files } = extractFiles(body)
const { clone, files } = extractFiles(body, '', customIsExtractableFile)
const payload = serializeFetchParameter(clone, 'Payload')

if (files.size) {
Expand All @@ -149,7 +159,7 @@ exports.createUploadLink = ({
// GraphQL multipart request spec:
// https://github.com/jaydenseric/graphql-multipart-request-spec

const form = new FormData()
const form = new CustomFormData()

form.append('operations', payload)

Expand All @@ -162,7 +172,7 @@ exports.createUploadLink = ({

i = 0
files.forEach((paths, file) => {
form.append(++i, file, file.name)
customAppendFile(form, ++i, file)
})

options.body = form
Expand All @@ -181,7 +191,7 @@ exports.createUploadLink = ({
}
}

linkFetch(uri, options)
customFetch(uri, options)
.then(response => {
// Forward the response on the context.
operation.setContext({ response })
Expand Down Expand Up @@ -213,3 +223,24 @@ exports.createUploadLink = ({
})
})
}

/**
* Adds a file to an existing multipart request. By default, simply appends the passed file without any special processing. The `name` property of the `file` object is used as the file name.
* @kind function
* @name defaultAppendFile
* @param {object} form FormData object to which to append the specified file.
* @param {string} name The name under which the file should be appended.
* @param {object} file The file to be appended.
* @returns {void}
* @example <caption>Default appendFile function.</caption>
* ```js
* i = 0
* files.forEach((paths, file) => {
* defaultAppendFile(form, ++i, file)
* })
* ```
*/
function defaultAppendFile(form, name, file) {
form.append(name, file, file.name)
}
exports.defaultAppendFile = defaultAppendFile

0 comments on commit 2f2e2b5

Please sign in to comment.