UNPKG

react-relay-network-modern

Version:

Network Layer for React Relay and Express (Batch Queries, AuthToken, Logging, Retry)

79 lines (69 loc) 2.42 kB
/* @flow */ /* eslint-disable no-param-reassign, prefer-const */ import { createRequestError } from './createRequestError'; import RelayResponse from './RelayResponse'; import type { Middleware, MiddlewareNextFn, RelayRequestAny, MiddlewareRaw, MiddlewareRawNextFn, FetchResponse, } from './definition'; function runFetch(req: RelayRequestAny): Promise<FetchResponse> { let { url } = req.fetchOpts; if (!url) url = '/graphql'; if (!req.fetchOpts.headers.Accept) req.fetchOpts.headers.Accept = '*/*'; if (!req.fetchOpts.headers['Content-Type'] && !req.isFormData()) { req.fetchOpts.headers['Content-Type'] = 'application/json'; } return fetch(url, (req.fetchOpts: any)); } // convert fetch response to RelayResponse object const convertResponse: (next: MiddlewareRawNextFn) => MiddlewareNextFn = (next) => async (req) => { const resFromFetch = await next(req); const res = await RelayResponse.createFromFetch(resFromFetch); if (res.status && res.status >= 400) { throw createRequestError(req, res); } return res; }; export default function fetchWithMiddleware( req: RelayRequestAny, middlewares: Middleware[], // works with RelayResponse rawFetchMiddlewares: MiddlewareRaw[], // works with raw fetch response noThrow?: boolean ): Promise<RelayResponse> { // $FlowFixMe const wrappedFetch: MiddlewareNextFn = compose( ...middlewares, convertResponse, ...rawFetchMiddlewares )((runFetch: any)); return wrappedFetch(req).then((res) => { if (!noThrow && (!res || res.errors || !res.data)) { throw createRequestError(req, res); } return res; }); } /** * Composes single-argument functions from right to left. The rightmost * function can take multiple arguments as it provides the signature for * the resulting composite function. * * @param {...Function} funcs The functions to compose. * @returns {Function} A function obtained by composing the argument functions * from right to left. For example, compose(f, g, h) is identical to doing * (...args) => f(g(h(...args))). */ function compose(...funcs) { if (funcs.length === 0) { return (arg) => arg; } else { const last = funcs[funcs.length - 1]; const rest = funcs.slice(0, -1); // $FlowFixMe - Suppress error about promise not being callable return (...args) => rest.reduceRight((composed, f) => f((composed: any)), last(...args)); } }