GraphQL Upload#
In GQty you can add File Upload support easily, following the GraphQL multipart request specification.
Preparation#
Normally, in the API servers, they implement graphql-upload, which could be implemented with mercurius-upload for Mercurius, or in GraphQL EZ with the GraphQL Upload EZ Plugin.
Meanwhile in the client, to follow the GraphQL multipart spec, you can easily use extract-files.
yarn add extract-files@11.0.0
yarn add -D @types/extract-files@8.1.1pnpm add extract-files@11.0.0
pnpm add -D @types/extract-files@8.1.1npm install extract-files@11.0.0
npm install -D @types/extract-files@8.1.1And then, use it in your QueryFetcher, like the following example:
Compatible with browser's File and Blob, and React Native using ReactNativeFile
import { extractFiles } from 'extract-files';
// ...
const queryFetcher: QueryFetcher = async function (query, variables) {
  const extracted = extractFiles({
    query,
    variables,
  });
  if (extracted.files.size > 0) {
    const form = new FormData();
    form.append('operations', JSON.stringify(extracted.clone));
    const map: Record<number, string[]> = {};
    let i = 0;
    extracted.files.forEach((paths) => {
      map[++i] = paths;
    });
    form.append('map', JSON.stringify(map));
    i = 0;
    extracted.files.forEach((_paths, file) => {
      form.append(++i + '', file as File);
    });
    const response = await fetch('/api/graphql', {
      method: 'POST',
      headers: {},
      body: form,
      mode: 'cors',
    });
    const json = await response.json();
    return json;
  }
  // Fallback to regular queries
  const response = await fetch('/api/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query,
      variables,
    }),
    mode: 'cors',
  });
  const json = await response.json();
  return json;
};
Usage#
Core#
Since the images are not serializable, GQty might be confused while
using them, that's why you have to specify a special option nonSerializableVariables in your resolveds
import { resolved, mutation } from '../gqty';
resolved(
  () => {
    return mutation.uploadFile({
      file,
    })!;
  },
  {
    //...
    // You should specify this flag
    nonSerializableVariables: true,
  }
)
  .then((data) => {
    // ...
  })
  .catch((error) => {
    // ...
  });
React#
Since the images are not serializable, GQty might be confused while
using them, that's why you have to specify a special option nonSerializableVariables in your useMutations
const [uploadFile, { isLoading, data, error }] = useMutation(
  (mutation, file: File) => {
    return mutation.uploadFile({
      file,
    })!;
  },
  {
    // ...
    // You should specify this flag
    nonSerializableVariables: true,
  }
);