diff --git a/README.md b/README.md index 14e39616..d8d0c618 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,23 @@ export default Ember.Route.extend({ If your errors aren't standard, the helper function for that error type can be used as the base to build your custom detection function. +## Usage with Ember Data + +Ember AJAX provides a mixin that can be used in an Ember Data Adapter to avoid the networking code provided by Ember Data and rely on Ember AJAX instead. This serves as a first step toward true integration of Ember AJAX into Ember Data. + +To use the mixin, you can include the mixin into an Adapter, like so: + +```javascript +// app/adapters/application.js +import DS from 'ember-data'; +import AjaxServiceSupport from 'ember-ajax/mixins/ajax-support'; + +export default DS.JSONAPIAdapter.extend(AjaxServiceSupport); +``` + +That's all the configuration required! If you want to customize the adapter, such as using an alternative AJAX service (like one you extended yourself), hooks to do so are provided; check out the mixin's implementation for details. + +Note that instead of using the Ember Data error checking code in your application, you should use the ones provided by Ember AJAX. ## Testing diff --git a/addon/mixins/ajax-request.js b/addon/mixins/ajax-request.js index bf574c94..a1f17dba 100644 --- a/addon/mixins/ajax-request.js +++ b/addon/mixins/ajax-request.js @@ -34,8 +34,10 @@ const { isNone, merge, run, + runInDebug, Test, - testing + testing, + warn } = Ember; const JSONAPIContentType = 'application/vnd.api+json'; @@ -121,6 +123,14 @@ export default Mixin.create({ }; hash.error = (jqXHR, textStatus, errorThrown) => { + runInDebug(function() { + let message = `The server returned an empty string for ${requestData.type} ${url}, which cannot be parsed into a valid JSON. Return either null or {}.`; + let validJSONString = !(textStatus === 'parsererror' && jqXHR.responseText === ''); + warn(message, validJSONString, { + id: 'ds.adapter.returned-empty-string-as-JSON' + }); + }); + const payload = this.parseErrorResponse(jqXHR.responseText) || errorThrown; let response; diff --git a/addon/mixins/ajax-support.js b/addon/mixins/ajax-support.js new file mode 100644 index 00000000..25f8e855 --- /dev/null +++ b/addon/mixins/ajax-support.js @@ -0,0 +1,46 @@ +import Ember from 'ember'; + +const { + Mixin, + inject: { service }, + computed: { alias } +} = Ember; + +export default Mixin.create({ + + /** + * The AJAX service to send requests through + * + * @property {AjaxService} ajaxService + * @public + */ + ajaxService: service('ajax'), + + /** + * @property {string} host + * @public + */ + host: alias('ajaxService.host'), + + /** + * @property {string} namespace + * @public + */ + namespace: alias('ajaxService.namespace'), + + /** + * @property {object} headers + * @public + */ + headers: alias('ajaxService.headers'), + + ajax(url, type, options) { + options = this.ajaxOptions(...arguments); + return this.get('ajaxService').request(url, options); + }, + + ajaxOptions(url, type, options = {}) { + options.type = type; + return this.get('ajaxService').options(url, options); + } +}); diff --git a/package.json b/package.json index be398a1c..93ed1f46 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "ember-cli-release": "0.2.8", "ember-cli-sri": "^2.1.0", "ember-cli-uglify": "^1.2.0", + "ember-data": "^2.5.3", "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.1", "ember-export-application-global": "^1.0.4", diff --git a/tests/acceptance/ember-data-integration-test.js b/tests/acceptance/ember-data-integration-test.js new file mode 100644 index 00000000..3348d67e --- /dev/null +++ b/tests/acceptance/ember-data-integration-test.js @@ -0,0 +1,38 @@ +import { test } from 'qunit'; +import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; + +import Pretender from 'pretender'; +import { jsonResponse } from 'dummy/tests/helpers/json'; + +let server; +moduleForAcceptance('Acceptance | ember data integration', { + beforeEach() { + server = new Pretender(); + }, + afterEach() { + server.shutdown(); + } +}); + +test('ember data adapter uses ember-ajax mixin', function(assert) { + assert.expect(2); + + server.get('api/posts/1', function() { + assert.ok(true, 'Used the ember-ajax integration'); + return jsonResponse(200, { + data: { + id: 1, + type: 'post', + attributes: { + title: 'Foo' + } + } + }); + }); + + visit('/ember-data-test'); + + andThen(function() { + assert.equal(currentURL(), '/ember-data-test'); + }); +}); diff --git a/tests/dummy/app/adapters/application.js b/tests/dummy/app/adapters/application.js new file mode 100644 index 00000000..e7006df3 --- /dev/null +++ b/tests/dummy/app/adapters/application.js @@ -0,0 +1,8 @@ +import DS from 'ember-data'; +import AjaxServiceSupport from 'ember-ajax/mixins/ajax-support'; + +const { JSONAPIAdapter } = DS; + +export default JSONAPIAdapter.extend(AjaxServiceSupport, { + namespace: 'api' +}); diff --git a/tests/dummy/app/models/post.js b/tests/dummy/app/models/post.js new file mode 100644 index 00000000..5801c409 --- /dev/null +++ b/tests/dummy/app/models/post.js @@ -0,0 +1,6 @@ +import Model from 'ember-data/model'; +import attr from 'ember-data/attr'; + +export default Model.extend({ + title: attr('string') +}); diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index 3bba78eb..bcd5b843 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -6,6 +6,7 @@ const Router = Ember.Router.extend({ }); Router.map(function() { + this.route('ember-data-test'); }); export default Router; diff --git a/tests/dummy/app/routes/ember-data-test.js b/tests/dummy/app/routes/ember-data-test.js new file mode 100644 index 00000000..36961aa6 --- /dev/null +++ b/tests/dummy/app/routes/ember-data-test.js @@ -0,0 +1,7 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model() { + return this.store.find('post', 1); + } +}); diff --git a/tests/dummy/app/templates/ember-data-test.hbs b/tests/dummy/app/templates/ember-data-test.hbs new file mode 100644 index 00000000..c24cd689 --- /dev/null +++ b/tests/dummy/app/templates/ember-data-test.hbs @@ -0,0 +1 @@ +{{outlet}}