Skip to content

Commit

Permalink
Make fetch implementation configurable
Browse files Browse the repository at this point in the history
Currently apollo-client relies on the globally available `fetch` api
which causes a number of problems. In the browser apollo-client uses a
polyfill which "pollutes" the global scope. This is something a library
should probably rather not do.

This change is based on previous discussion and work done in
apollographql#661 and apollographql#645.
  • Loading branch information
ctavan committed Aug 7, 2017
1 parent d50ac84 commit abe6363
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 72 deletions.
8 changes: 8 additions & 0 deletions fetch-mock.typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,14 @@ declare namespace FetchMock {
lot of array buffers, it can be useful to default to `false`
*/
configure(opts: Object): void;
/**
* Configure the fetch implementation to be used
*/
setImplementations(implementations: Object): void;
/**
* Return a sandbox
*/
sandbox(): FetchMockStatic;
}
}

Expand Down
8 changes: 8 additions & 0 deletions fetch-ponyfill.typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Type definitions for fetch-ponyfill 4.1.0
// Project: https://github.com/qubyte/fetch-ponyfill

declare function fetchPonyfill(options?: any): any

declare module 'fetch-ponyfill' {
export = fetchPonyfill;
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@
"license": "MIT",
"dependencies": {
"apollo-link-core": "^0.2.0",
"fetch-ponyfill": "^4.1.0",
"graphql": "^0.10.0",
"graphql-anywhere": "^3.0.1",
"graphql-tag": "^2.0.0",
"redux": "^3.4.0",
"symbol-observable": "^1.0.2",
"whatwg-fetch": "^2.0.0"
"symbol-observable": "^1.0.2"
},
"devDependencies": {
"@types/benchmark": "1.0.30",
Expand Down
10 changes: 6 additions & 4 deletions src/transport/batchedNetworkInterface.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { ExecutionResult } from 'graphql';

import 'whatwg-fetch';

import {
BaseNetworkInterface,
HTTPNetworkInterface,
Expand Down Expand Up @@ -43,13 +41,15 @@ export class HTTPBatchedNetworkInterface extends BaseNetworkInterface {
batchInterval = 10,
batchMax = 0,
fetchOpts,
fetch = undefined,
}: {
uri: string;
batchInterval?: number;
batchMax?: number;
fetchOpts: RequestInit;
fetch?: any;
}) {
super(uri, fetchOpts);
super(uri, fetchOpts, fetch);

if (typeof batchInterval !== 'number') {
throw new Error(`batchInterval must be a number, got ${batchInterval}`);
Expand Down Expand Up @@ -236,7 +236,7 @@ export class HTTPBatchedNetworkInterface extends BaseNetworkInterface {
return printRequest(request);
});

return fetch(this._uri, {
return this._fetch(this._uri, {
...this._opts,
body: JSON.stringify(printedRequests),
method: 'POST',
Expand All @@ -255,6 +255,7 @@ export interface BatchingNetworkInterfaceOptions {
batchInterval?: number;
batchMax?: number;
opts?: RequestInit;
fetch?: any;
}

export function createBatchingNetworkInterface(
Expand All @@ -270,5 +271,6 @@ export function createBatchingNetworkInterface(
batchInterval: options.batchInterval,
batchMax: options.batchMax,
fetchOpts: options.opts || {},
fetch: options.fetch,
});
}
20 changes: 15 additions & 5 deletions src/transport/networkInterface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'whatwg-fetch';

import { ExecutionResult, DocumentNode } from 'graphql';

import { print } from 'graphql/language/printer';
Expand All @@ -12,6 +10,8 @@ import { removeConnectionDirectiveFromDocument } from '../queries/queryTransform

import { Observable } from '../util/Observable';

import fetchPonyfill = require('fetch-ponyfill');

/**
* This is an interface that describes an GraphQL document to be sent
* to the server.
Expand Down Expand Up @@ -100,8 +100,13 @@ export class BaseNetworkInterface implements NetworkInterface {
public _afterwares: AfterwareInterface[] | BatchAfterwareInterface[];
public _uri: string;
public _opts: RequestInit;
public _fetch: any;

constructor(uri: string | undefined, opts: RequestInit = {}) {
constructor(
uri: string | undefined,
opts: RequestInit = {},
fetch: any | undefined,
) {
if (!uri) {
throw new Error('A remote endpoint is required for a network layer');
}
Expand All @@ -112,6 +117,7 @@ export class BaseNetworkInterface implements NetworkInterface {

this._uri = uri;
this._opts = { ...opts };
this._fetch = fetch || fetchPonyfill();

this._middlewares = [];
this._afterwares = [];
Expand Down Expand Up @@ -184,7 +190,7 @@ export class HTTPFetchNetworkInterface extends BaseNetworkInterface {
request,
options,
}: RequestAndOptions): Promise<Response> {
return fetch(this._uri, {
return this._fetch(this._uri, {
...this._opts,
body: JSON.stringify(printRequest(request)),
method: 'POST',
Expand Down Expand Up @@ -277,6 +283,7 @@ export class HTTPFetchNetworkInterface extends BaseNetworkInterface {
export interface NetworkInterfaceOptions {
uri?: string;
opts?: RequestInit;
fetch?: any;
}

export function createNetworkInterface(
Expand All @@ -291,6 +298,7 @@ export function createNetworkInterface(

let uri: string | undefined;
let opts: RequestInit | undefined;
let fetch: any | undefined;

// We want to change the API in the future so that you just pass all of the options as one
// argument, so even though the internals work with two arguments we're warning here.
Expand All @@ -299,9 +307,11 @@ export function createNetworkInterface(
as of Apollo Client 0.5. Please pass it as the "uri" property of the network interface options.`);
opts = secondArgOpts.opts;
uri = uriOrInterfaceOpts;
fetch = secondArgOpts.fetch;
} else {
opts = uriOrInterfaceOpts.opts;
uri = uriOrInterfaceOpts.uri;
fetch = uriOrInterfaceOpts.fetch;
}
return new HTTPFetchNetworkInterface(uri, opts);
return new HTTPFetchNetworkInterface(uri, opts, fetch);
}
38 changes: 19 additions & 19 deletions test/batchedNetworkInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ import { ExecutionResult } from 'graphql';

import gql from 'graphql-tag';

import 'whatwg-fetch';

declare var fetch: any;

describe('HTTPBatchedNetworkInterface', () => {
// Helper method that tests a roundtrip given a particular set of requests to the
// batched network interface and the
Expand All @@ -41,14 +37,6 @@ describe('HTTPBatchedNetworkInterface', () => {
opts?: RequestInit;
}) => {
const url = 'http://fake.com/graphql';
const batchedNetworkInterface = new HTTPBatchedNetworkInterface({
uri: url,
batchInterval: 10,
fetchOpts: opts,
});

batchedNetworkInterface.use(middlewares);
batchedNetworkInterface.useAfter(afterwares);

const printedRequests: Array<any> = [];
const resultList: Array<any> = [];
Expand All @@ -57,7 +45,7 @@ describe('HTTPBatchedNetworkInterface', () => {
resultList.push(result);
});

fetch =
const fetch =
fetchFunc ||
createMockFetch({
url,
Expand All @@ -75,6 +63,16 @@ describe('HTTPBatchedNetworkInterface', () => {
result: createMockedIResponse(resultList),
});

const batchedNetworkInterface = new HTTPBatchedNetworkInterface({
uri: url,
batchInterval: 10,
fetchOpts: opts,
fetch,
});

batchedNetworkInterface.use(middlewares);
batchedNetworkInterface.useAfter(afterwares);

return batchedNetworkInterface
.batchQuery(requestResultPairs.map(({ request }) => request))
.then(results => {
Expand Down Expand Up @@ -459,18 +457,13 @@ describe('HTTPBatchedNetworkInterface', () => {
`;

const url = 'http://fake.com/graphql';
const batchedNetworkInterface = new HTTPBatchedNetworkInterface({
uri: url,
batchInterval: 10,
fetchOpts: {},
});

const printedRequests: Array<any> = [
printRequest({ query: authorQuery }),
];
const resultList: Array<any> = [authorResult];

fetch = createMockFetch({
const fetch = createMockFetch({
url,
opts: {
body: JSON.stringify(printedRequests),
Expand All @@ -483,6 +476,13 @@ describe('HTTPBatchedNetworkInterface', () => {
result: createMockedIResponse(resultList),
});

const batchedNetworkInterface = new HTTPBatchedNetworkInterface({
uri: url,
batchInterval: 10,
fetchOpts: {},
fetch,
});

return batchedNetworkInterface
.batchQuery([{ query: authorQueryWithConnection }])
.then(results => {
Expand Down
Loading

0 comments on commit abe6363

Please sign in to comment.