Skip to content

Commit

Permalink
[BUGFIX release] Remove ember-fetch dependency.
Browse files Browse the repository at this point in the history
This change removes ember-fetch as a direct dependency of ember-data,
and allows for this dependency to be provided by the host application
or for users to directly use native fetch.

Having `ember-fetch` as a direct dependency of ember-data has proven
troublesome. There are issues using ember-fetch as a nested dependency
(these are documented in the ember-fetch README), but it is also quite
difficult for ember-data to ensure that the versions of `ember-fetch`
provided will actually include the correct version (duplicated addon
merging in the ember-cli addon space is complicated and error prone).

This change moves the `determineBodyPromise` and `serializeQueryParams`
helper functions directly into `@ember-data/adapter`. A future version
of ember-fetch will drop these utilities (as well as the ember-data
adapter mixin). In addition, this also enables usage of the global
`fetch` if a `fetch` module is not provided.
  • Loading branch information
rwjblue committed May 1, 2019
1 parent 81af0fb commit cd66d17
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 10 deletions.
2 changes: 1 addition & 1 deletion packages/-ember-data/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
"ember-cli-test-info": "^1.0.0",
"ember-cli-typescript": "^2.0.1",
"ember-cli-version-checker": "^3.1.2",
"ember-fetch": "^6.5.0",
"ember-inflector": "^3.0.0",
"inflection": "^1.12.0",
"resolve": "^1.8.1",
Expand Down Expand Up @@ -84,6 +83,7 @@
"ember-decorators-polyfill": "^1.0.4",
"ember-disable-prototype-extensions": "*",
"ember-export-application-global": "*",
"ember-fetch": "^6.5.0",
"ember-load-initializers": "*",
"ember-maybe-import-regenerator": "*",
"ember-qunit": "*",
Expand Down
3 changes: 3 additions & 0 deletions packages/adapter/addon/-private/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export { default as parseResponseHeaders } from './utils/parse-response-headers';
export { determineBodyPromise } from './utils/determine-body-promise';
export { serializeQueryParams } from './utils/serialize-query-params';
export { default as fetch } from './utils/fetch';
30 changes: 30 additions & 0 deletions packages/adapter/addon/-private/utils/determine-body-promise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Function that always attempts to parse the response as json, and if an error is thrown,
* returns `undefined` if the response is successful and has a status code of 204 (No Content),
* or 205 (Reset Content) or if the request method was 'HEAD', and the plain payload otherwise.
*/
export function determineBodyPromise(
response: Response,
requestData: JQueryAjaxSettings
): Promise<object | string | undefined> {
return response.text().then(function(payload) {
let ret: string | object | undefined = payload;
try {
ret = JSON.parse(payload);
} catch (error) {
if (!(error instanceof SyntaxError)) {
throw error;
}
const status = response.status;
if (
response.ok &&
(status === 204 || status === 205 || requestData.method === 'HEAD')
) {
ret = undefined;
} else {
console.warn('This response was unable to be parsed as json.', payload);
}
}
return ret;
});
}
17 changes: 17 additions & 0 deletions packages/adapter/addon/-private/utils/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import require, { has } from 'require';

type MaybeFetch = {
(input: RequestInfo, init?: RequestInit | undefined): Promise<Response>;
} | null;

let _fetch: MaybeFetch = null;

if (has('fetch')) {
// use `fetch` module by default, this is commonly provided by ember-fetch
_fetch = require('fetch').default;
} else if (typeof fetch === 'function') {
// fallback to using global fetch
_fetch = fetch;
}

export default _fetch;
69 changes: 69 additions & 0 deletions packages/adapter/addon/-private/utils/serialize-query-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const RBRACKET = /\[\]$/;

function isPlainObject(obj: any): boolean {
return Object.prototype.toString.call(obj) === '[object Object]';
}

/**
* Helper function that turns the data/body of a request into a query param string.
* This is directly copied from jQuery.param.
*/
export function serializeQueryParams(
queryParamsObject: object | string
): string {
var s: any[] = [];

function buildParams(prefix: string, obj: any) {
var i, len, key;

if (prefix) {
if (Array.isArray(obj)) {
for (i = 0, len = obj.length; i < len; i++) {
if (RBRACKET.test(prefix)) {
add(s, prefix, obj[i]);
} else {
buildParams(
prefix + '[' + (typeof obj[i] === 'object' ? i : '') + ']',
obj[i]
);
}
}
} else if (isPlainObject(obj)) {
for (key in obj) {
buildParams(prefix + '[' + key + ']', obj[key]);
}
} else {
add(s, prefix, obj);
}
} else if (Array.isArray(obj)) {
for (i = 0, len = obj.length; i < len; i++) {
add(s, obj[i].name, obj[i].value);
}
} else {
for (key in obj) {
buildParams(key, obj[key]);
}
}
return s;
}

return buildParams('', queryParamsObject)
.join('&')
.replace(/%20/g, '+');
}

/**
* Part of the `serializeQueryParams` helper function.
*/
function add(s: Array<any>, k: string, v?: string | (() => string)) {
// Strip out keys with undefined value and replace null values with
// empty strings (mimics jQuery.ajax)
if (v === undefined) {
return;
} else if (v === null) {
v = '';
}

v = typeof v === 'function' ? v() : v;
s[s.length] = `${encodeURIComponent(k)}=${encodeURIComponent(v)}`;
}
15 changes: 9 additions & 6 deletions packages/adapter/addon/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
@module ember-data
*/

import fetch from 'fetch';
import serializeQueryParams from 'ember-fetch/utils/serialize-query-params';
import determineBodyPromise from 'ember-fetch/utils/determine-body-promise';

import RSVP, { Promise as EmberPromise } from 'rsvp';
import { get, computed } from '@ember/object';
import { getOwner } from '@ember/application';
import { run } from '@ember/runloop';
import Adapter, { BuildURLMixin } from '@ember-data/adapter';
import { assign } from '@ember/polyfills';
import { parseResponseHeaders } from '@ember-data/adapter/-private';
import {
determineBodyPromise,
fetch,
parseResponseHeaders,
serializeQueryParams,
} from './-private';
import {
AdapterError,
InvalidError,
Expand Down Expand Up @@ -301,7 +302,9 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, {

useFetch: computed(function() {
let ENV = getOwner(this).resolveRegistration('config:environment');
return (ENV && ENV._JQUERY_INTEGRATION) === false || jQ === undefined;
let shouldUseFetch = (ENV && ENV._JQUERY_INTEGRATION) === false || jQ === undefined;

return shouldUseFetch;
}),

/**
Expand Down
20 changes: 17 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3377,7 +3377,16 @@ browserslist@^3.2.6:
caniuse-lite "^1.0.30000844"
electron-to-chromium "^1.3.47"

browserslist@^4.0.0, browserslist@^4.5.2, browserslist@^4.5.4:
browserslist@^4.0.0:
version "4.5.6"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.5.6.tgz#ea42e8581ca2513fa7f371d4dd66da763938163d"
integrity sha512-o/hPOtbU9oX507lIqon+UvPYqpx3mHc8cV3QemSBTXwkG8gSQSK6UKvXcE/DcleU3+A59XTUHyCvZ5qGy8xVAg==
dependencies:
caniuse-lite "^1.0.30000963"
electron-to-chromium "^1.3.127"
node-releases "^1.1.17"

browserslist@^4.5.2, browserslist@^4.5.4:
version "4.5.5"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.5.5.tgz#fe1a352330d2490d5735574c149a85bc18ef9b82"
integrity sha512-0QFO1r/2c792Ohkit5XI8Cm8pDtZxgNl2H6HU4mHrpYz7314pEYcsAVVatM0l/YmxPnEzh9VygXouj4gkFUTKA==
Expand Down Expand Up @@ -3591,7 +3600,7 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"

caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000960:
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000960, caniuse-lite@^1.0.30000963:
version "1.0.30000963"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000963.tgz#5be481d5292f22aff5ee0db4a6c049b65b5798b1"
integrity sha512-n4HUiullc7Lw0LyzpeLa2ffP8KxFBGdxqD/8G3bSL6oB758hZ2UE2CVK+tQN958tJIi0/tfpjAc67aAtoHgnrQ==
Expand Down Expand Up @@ -4577,6 +4586,11 @@ electron-to-chromium@^1.3.124, electron-to-chromium@^1.3.47:
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.127.tgz#9b34d3d63ee0f3747967205b953b25fe7feb0e10"
integrity sha512-1o25iFRf/dbgauTWalEzmD1EmRN3a2CzP/K7UVpYLEBduk96LF0FyUdCcf4Ry2mAWJ1VxyblFjC93q6qlLwA2A==

electron-to-chromium@^1.3.127:
version "1.3.128"
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.128.tgz#1f9ffa31397da2f220d583dbb2b763e365dfbbc5"
integrity sha512-1QK+KELj1mhC9iE7grSP9PP2f06F85UgTs0M9qjuvSuKwxbyifhyPB8dZ27IlYvzMBnLtO4oHNBKTQoN6Tg5mg==

ember-assign-polyfill@^2.6.0:
version "2.6.0"
resolved "https://registry.npmjs.org/ember-assign-polyfill/-/ember-assign-polyfill-2.6.0.tgz#07847e3357ee35b33f886a0b5fbec6873f6860eb"
Expand Down Expand Up @@ -8618,7 +8632,7 @@ node-notifier@^5.0.1:
shellwords "^0.1.1"
which "^1.3.0"

node-releases@^1.1.14:
node-releases@^1.1.14, node-releases@^1.1.17:
version "1.1.17"
resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.17.tgz#71ea4631f0a97d5cd4f65f7d04ecf9072eac711a"
integrity sha512-/SCjetyta1m7YXLgtACZGDYJdCSIBAWorDWkGCGZlydP2Ll7J48l7j/JxNYZ+xsgSPbWfdulVS/aY+GdjUsQ7Q==
Expand Down

0 comments on commit cd66d17

Please sign in to comment.