From fc5a97cb64ae2bf87acf5f00824a07b36a22251a Mon Sep 17 00:00:00 2001 From: gearnode Date: Fri, 28 Feb 2025 10:57:35 +0100 Subject: [PATCH] Add support for file uploads in Relay Environment Add support for file uploads in RelayEnvironment by implementing multipart form[1] handling via FormData when uploadables are present. Maintain backward compatibility for standard GraphQL queries. [1] https://github.com/jaydenseric/graphql-multipart-request-spec Signed-off-by: gearnode --- apps/console/src/RelayEnvironment.ts | 63 ++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/apps/console/src/RelayEnvironment.ts b/apps/console/src/RelayEnvironment.ts index e31462199..cc88fb508 100644 --- a/apps/console/src/RelayEnvironment.ts +++ b/apps/console/src/RelayEnvironment.ts @@ -7,21 +7,60 @@ import { } from "relay-runtime"; import { buildEndpoint } from "./utils"; -const fetchRelay: FetchFunction = async (request, variables) => { - const response = await fetch(buildEndpoint("/console/v1/query"), { - method: "POST", - credentials: "include", - headers: { - Accept: - "application/graphql-response+json; charset=utf-8, application/json; charset=utf-8", - "Content-Type": "application/json", - }, - body: JSON.stringify({ +const fetchRelay: FetchFunction = async (request, variables, _, uploadables) => { + const requestInit: RequestInit = { + method: 'POST', + credentials: 'include', + headers: {}, + }; + + + if (uploadables) { + const formData = new FormData(); + formData.append( + 'operations', + JSON.stringify({ + operationName: request.name, + query: request.text, + variables: variables, + }) + ); + + + const uploadableMap: { + [key: string]: string[]; + } = {}; + + Object.keys(uploadables).forEach((key, index) => { + if (Object.prototype.hasOwnProperty.call(uploadables, key)) { + uploadableMap[index] = [`variables.${key}`]; + } + }); + + formData.append('map', JSON.stringify(uploadableMap)); + + Object.keys(uploadables).forEach((key, index) => { + if (Object.prototype.hasOwnProperty.call(uploadables, key)) { + formData.append(index.toString(), uploadables[key]); + } + }); + + requestInit.body = formData; + + } else { + requestInit.headers = { + "Accept": "application/graphql-response+json; charset=utf-8, application/json; charset=utf-8", + "Content-Type": "application/json" + } + + requestInit.body = JSON.stringify({ operationName: request.name, query: request.text, variables, - }), - }); + }); + } + + const response = await fetch(buildEndpoint("/console/v1/query"), requestInit); const json = await response.json();