A terminating Apollo Link for Apollo Client that fetches a GraphQL multipart request if the GraphQL variables contain files (by default FileList
, File
, or Blob
instances), or else fetches a regular GraphQL POST or GET request (depending on the config and GraphQL operation).
To install with npm, run:
npm install apollo-upload-client
Polyfill any required globals (see Requirements) that are missing in your server and client environments.
Remove any uri
, credentials
, or headers
options from the ApolloClient
constructor.
Apollo Client can only have 1 terminating Apollo Link that sends the GraphQL requests; if one such as HttpLink
is already setup, remove it.
Initialize the client with a terminating Apollo Link using the function createUploadLink
.
Also ensure the GraphQL server implements the GraphQL multipart request spec and that uploads are handled correctly in resolvers.
Use FileList
, File
, or Blob
instances anywhere within query or mutation variables to send a GraphQL multipart request.
See also the example API and client.
FileList
import { gql, useMutation } from "@apollo/client";
const MUTATION = gql`
mutation ($files: [Upload!]!) {
uploadFiles(files: $files) {
success
}
}
`;
function UploadFiles() {
const [mutate] = useMutation(MUTATION);
return (
<input
type="file"
multiple
required
onChange={({ target: { validity, files } }) => {
if (validity.valid)
mutate({
variables: {
files,
},
});
}}
/>
);
}
File
import { gql, useMutation } from "@apollo/client";
const MUTATION = gql`
mutation ($file: Upload!) {
uploadFile(file: $file) {
success
}
}
`;
function UploadFile() {
const [mutate] = useMutation(MUTATION);
return (
<input
type="file"
required
onChange={({
target: {
validity,
files: [file],
},
}) => {
if (validity.valid)
mutate({
variables: {
file,
},
});
}}
/>
);
}
Blob
import { gql, useMutation } from "@apollo/client";
const MUTATION = gql`
mutation ($file: Upload!) {
uploadFile(file: $file) {
success
}
}
`;
function UploadFile() {
const [mutate] = useMutation(MUTATION);
return (
<input
type="text"
required
onChange={({ target: { validity, value } }) => {
if (validity.valid) {
const file = new Blob([value], { type: "text/plain" });
// Optional, defaults to `blob`.
file.name = "text.txt";
mutate({
variables: {
file,
},
});
}
}}
/>
);
}
^18.15.0 || >=20.4.0
.> 0.5%, not OperaMini all, not dead
.Consider polyfilling:
Projects must configure TypeScript to use types from the ECMAScript modules that have a // @ts-check
comment:
compilerOptions.allowJs
should be true
.compilerOptions.maxNodeModuleJsDepth
should be reasonably large, e.g. 10
.compilerOptions.module
should be "node16"
or "nodenext"
.The npm package apollo-upload-client
features optimal JavaScript module design. It doesn’t have a main index module, so use deep imports from the ECMAScript modules that are exported via the package.json
field exports
: