UNPKG

@omnigraph/odata

Version:
126 lines (125 loc) 6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDataloaderFactory = getDataloaderFactory; const tslib_1 = require("tslib"); const dataloader_1 = tslib_1.__importDefault(require("dataloader")); const http_string_parser_1 = require("http-string-parser"); const url_join_1 = tslib_1.__importDefault(require("url-join")); const utils_1 = require("@graphql-mesh/utils"); const utils_2 = require("@graphql-tools/utils"); const fetch_1 = require("@whatwg-node/fetch"); function getDataloaderFactory({ fetchFn, endpoint, headersFactory, batchMode, }) { const DATALOADER_FACTORIES = { multipart: (context) => new dataloader_1.default(async (requests) => { let requestBody = ''; const requestBoundary = 'batch_' + Date.now(); for (const requestIndex in requests) { requestBody += `--${requestBoundary}\n`; const request = requests[requestIndex]; requestBody += `Content-Type: application/http\n`; requestBody += `Content-Transfer-Encoding:binary\n`; requestBody += `Content-ID: ${requestIndex}\n\n`; requestBody += `${request.method} ${request.url} HTTP/1.1\n`; request.headers?.forEach((value, key) => { requestBody += `${key}: ${value}\n`; }); if (request.body) { const bodyAsStr = await request.text(); requestBody += `Content-Length: ${bodyAsStr.length}`; requestBody += `\n`; requestBody += bodyAsStr; } requestBody += `\n`; } requestBody += `--${requestBoundary}--\n`; const batchHeaders = headersFactory({ context, env: process.env, }, 'POST'); batchHeaders['content-type'] = `multipart/mixed;boundary=${requestBoundary}`; const batchResponse = await fetchFn((0, url_join_1.default)(endpoint, '$batch'), { method: 'POST', body: requestBody, headers: batchHeaders, }); if (batchResponse.headers.get('content-type').includes('json')) { const batchResponseJson = await batchResponse.json(); return handleBatchJsonResults(batchResponseJson, requests); } const batchResponseText = await batchResponse.text(); const responseLines = batchResponseText.split('\n'); const responseBoundary = responseLines[0]; const actualResponse = responseLines.slice(1, responseLines.length - 2).join('\n'); const responseTextArr = actualResponse.split(responseBoundary); return responseTextArr.map(responseTextWithContentHeader => { const responseText = responseTextWithContentHeader.split('\n').slice(4).join('\n'); const { body, headers, statusCode, statusMessage } = (0, http_string_parser_1.parseResponse)(responseText); return new fetch_1.Response(body, { headers, status: parseInt(statusCode), statusText: statusMessage, }); }); }), json: (context) => new dataloader_1.default(async (requests) => { const batchHeaders = headersFactory({ context, env: process.env, }, 'POST'); batchHeaders['content-type'] = 'application/json'; const batchResponse = await fetchFn((0, url_join_1.default)(endpoint, '$batch'), { method: 'POST', body: JSON.stringify({ requests: await Promise.all(requests.map(async (request, index) => { const id = index.toString(); const url = request.url.replace(endpoint, ''); const method = request.method; const headers = {}; request.headers?.forEach((value, key) => { headers[key] = value; }); return { id, url, method, body: request.body && (await request.json()), headers, }; })), }), headers: batchHeaders, }); const batchResponseJson = await batchResponse.json(); return handleBatchJsonResults(batchResponseJson, requests); }), none: () => // We should refactor here new dataloader_1.default(requests => Promise.all(requests.map(async (request) => fetchFn(request.url, { method: request.method, body: request.body && (await request.text()), headers: (0, utils_1.getHeadersObj)(request.headers), })))), }; return (0, utils_2.memoize1)(DATALOADER_FACTORIES[batchMode]); } function handleBatchJsonResults(batchResponseJson, requests) { if ('error' in batchResponseJson) { throw (0, utils_2.createGraphQLError)(batchResponseJson.error.message, { extensions: batchResponseJson.error, }); } if (!('responses' in batchResponseJson)) { throw (0, utils_2.createGraphQLError)(batchResponseJson.ExceptionMessage || batchResponseJson.Message || `Batch Request didn't return a valid response.`, { extensions: batchResponseJson, }); } return requests.map((_req, index) => { const responseObj = batchResponseJson.responses.find((res) => res.id === index.toString()); return fetch_1.Response.json(responseObj.body, { status: responseObj.status, headers: responseObj.headers, }); }); }