Skip to content

Commit

Permalink
Add ability to abort a kfetch call. (#20700)
Browse files Browse the repository at this point in the history
* Split kfetch module into kfetch and kfetchAbortable sub-modules.
* Add abortcontroller-polyfill.
  • Loading branch information
cjcenizal authored Jul 12, 2018
1 parent 4ef3c5a commit d04bc1f
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 55 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"@kbn/test-subj-selector": "link:packages/kbn-test-subj-selector",
"@kbn/ui-framework": "link:packages/kbn-ui-framework",
"JSONStream": "1.1.1",
"abortcontroller-polyfill": "^1.1.9",
"angular": "1.6.9",
"angular-aria": "1.6.6",
"angular-elastic": "2.5.0",
Expand Down
4 changes: 4 additions & 0 deletions src/ui/public/chrome/chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ import _ from 'lodash';
import angular from 'angular';

import { metadata } from '../metadata';

// Polyfills
import 'babel-polyfill';
import 'whatwg-fetch';
import 'custom-event-polyfill';
import 'abortcontroller-polyfill';

import '../state_management/global_state';
import '../config';
import '../notify';
Expand Down
56 changes: 2 additions & 54 deletions src/ui/public/kfetch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,5 @@
* under the License.
*/

import 'isomorphic-fetch';
import url from 'url';
import chrome from '../chrome';
import { metadata } from '../metadata';
import { merge } from 'lodash';

class FetchError extends Error {
constructor(res, body) {
super(res.statusText);
this.res = res;
this.body = body;
Error.captureStackTrace(this, FetchError);
}
}

export async function kfetch(fetchOptions, kibanaOptions) {
// fetch specific options with defaults
const { pathname, query, ...combinedFetchOptions } = merge(
{
method: 'GET',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'kbn-version': metadata.version,
},
},
fetchOptions
);

// kibana specific options with defaults
const combinedKibanaOptions = {
prependBasePath: true,
...kibanaOptions,
};

const fullUrl = url.format({
pathname: combinedKibanaOptions.prependBasePath ? chrome.addBasePath(pathname) : pathname,
query,
});

const res = await fetch(fullUrl, combinedFetchOptions);

if (!res.ok) {
let body;
try {
body = await res.json();
} catch (err) {
// ignore error, may not be able to get body for response that is not ok
}
throw new FetchError(res, body);
}

return res.json();
}
export { kfetch } from './kfetch';
export { kfetchAbortable } from './kfetch_abortable';
77 changes: 77 additions & 0 deletions src/ui/public/kfetch/kfetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import 'isomorphic-fetch';
import url from 'url';
import chrome from '../chrome';
import { metadata } from '../metadata';
import { merge } from 'lodash';

class FetchError extends Error {
constructor(res, body) {
super(res.statusText);
this.res = res;
this.body = body;
Error.captureStackTrace(this, FetchError);
}
}

export function kfetch(fetchOptions, kibanaOptions) {
// fetch specific options with defaults
const { pathname, query, ...combinedFetchOptions } = merge(
{
method: 'GET',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'kbn-version': metadata.version,
},
},
fetchOptions,
);

// kibana specific options with defaults
const combinedKibanaOptions = {
prependBasePath: true,
...kibanaOptions,
};

const fullUrl = url.format({
pathname: combinedKibanaOptions.prependBasePath ? chrome.addBasePath(pathname) : pathname,
query,
});

const fetching = new Promise(async (resolve, reject) => {
const res = await fetch(fullUrl, combinedFetchOptions);

if (!res.ok) {
let body;
try {
body = await res.json();
} catch (err) {
// ignore error, may not be able to get body for response that is not ok
}
return reject(new FetchError(res, body));
}

resolve(res.json());
});

return fetching;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
*/

import fetchMock from 'fetch-mock';
import { kfetch } from './index';
import { kfetch } from './kfetch';

jest.mock('../chrome', () => ({
addBasePath: path => `myBase/${path}`,
}));

jest.mock('../metadata', () => ({
metadata: {
version: 'my-version',
Expand Down
40 changes: 40 additions & 0 deletions src/ui/public/kfetch/kfetch_abortable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { kfetch } from './kfetch';

function createAbortable() {
const abortController = new AbortController();
const { signal, abort } = abortController;

return {
signal,
abort: abort.bind(abortController),
};
}

export function kfetchAbortable(fetchOptions, kibanaOptions) {
const { signal, abort } = createAbortable();
const fetching = kfetch({ ...fetchOptions, signal }, kibanaOptions);

return {
fetching,
abort,
};
}
39 changes: 39 additions & 0 deletions src/ui/public/kfetch/kfetch_abortable.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { kfetchAbortable } from './kfetch_abortable';

jest.mock('../chrome', () => ({
addBasePath: path => `myBase/${path}`,
}));

jest.mock('../metadata', () => ({
metadata: {
version: 'my-version',
},
}));

describe('kfetchAbortable', () => {
it('should return an object with a fetching promise and an abort callback', () => {
const { fetching, abort } = kfetchAbortable({ pathname: 'my/path' });
expect(typeof fetching.then).toBe('function');
expect(typeof fetching.catch).toBe('function');
expect(typeof abort).toBe('function');
});
});
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,10 @@ [email protected]:
version "1.0.9"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"

abortcontroller-polyfill@^1.1.9:
version "1.1.9"
resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.1.9.tgz#9fefe359fda2e9e0932dc85e6106453ac393b2da"

accept-language-parser@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/accept-language-parser/-/accept-language-parser-1.5.0.tgz#8877c54040a8dcb59e0a07d9c1fde42298334791"
Expand Down

0 comments on commit d04bc1f

Please sign in to comment.