Skip to content
This repository was archived by the owner on Jan 22, 2026. It is now read-only.

Commit 836121c

Browse files
aarspixelhandler
authored andcommitted
Api host proxy mixin (#99)
* Sane default URL for adapter(s). Removes API_HOST_PROXY. * Puts generated url back into blueprint * API_HOST_PROXY as (example) mixin. * Adds comment about url property (adapter-blueprint) * Puts config import statement back
1 parent 31e0030 commit 836121c

14 files changed

Lines changed: 118 additions & 125 deletions

File tree

addon/adapters/application.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,22 @@ export default Ember.Object.extend(FetchMixin, Evented, {
3232
/**
3333
The url for the entity, e.g. /posts or /api/v1/posts
3434
35+
defaults to config.APP.API_HOST/config.APP.API_PATH/pluralize(type) if
36+
not set explicitly.
37+
3538
@property url
3639
@type String
3740
@required
3841
*/
39-
url: null,
42+
url: Ember.computed('type', {
43+
get() {
44+
const config = this.container.lookupFactory('config:environment');
45+
const enclosingSlashes = /^\/|\/$/g;
46+
const host = config.APP.API_HOST.replace(enclosingSlashes, '');
47+
const path = config.APP.API_PATH.replace(enclosingSlashes, '');
48+
return [host, path, pluralize(this.get('type'))].join('/');
49+
}
50+
}),
4051

4152
/**
4253
Find resource(s) using an id or a using a query `{id: '', query: {}}`
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
@module ember-jsonapi-resources
3+
@submodule adapter-api-host-proxy-mixin
4+
**/
5+
import Ember from 'ember';
6+
7+
/**
8+
Mixin to provide url rewrite for proxied api. Mostly used as example.
9+
10+
@class AdapterApiHostProxyMixin
11+
@static
12+
*/
13+
export default Ember.Mixin.create({
14+
fetchUrl: function(url) {
15+
const config = this.container.lookupFactory('config:environment');
16+
const proxy = config.APP.API_HOST_PROXY;
17+
const host = config.APP.API_HOST;
18+
if (proxy && host) {
19+
url = url.replace(host, proxy);
20+
}
21+
return url;
22+
}
23+
});

blueprints/jsonapi-adapter/files/__root__/__path__/__name__.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@ import config from '../config/environment';
44
export default <%= baseClass %>.extend({
55
type: '<%= entity %>',
66

7-
url: config.APP.API_PATH + '/<%= resource %>',
8-
9-
/*fetchUrl: function(url) {
10-
const proxy = config.APP.API_HOST_PROXY;
11-
const host = config.APP.API_HOST;
12-
if (proxy && host) {
13-
url = url.replace(proxy, host);
14-
}
15-
return url;
16-
}*/
7+
/*
8+
* url: full url/path to API endpoint for this resource.
9+
*
10+
* This property is optional, as the application adapter provides a sane
11+
* default combining config.APP.API_HOST, config.APP.API_PATH and type
12+
* through Ember computed properties. This is faster however, and provides
13+
* easy customization per adapter.
14+
*
15+
* Url is always fetched through #fetchUrl method to provide runtime
16+
* manipulation of the url, either per adapter or application-wide on the
17+
* application adapter. See AdapterApiHostProxyMixin for an example.
18+
*/
19+
url: [config.APP.API_HOST, config.APP.API_PATH, '<%= resource %>'].join('/')
1720
});

tests/acceptance/polymorphic-test.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import pictures1ImageableMock from 'fixtures/api/pictures/1/imageable';
99
import pictures5Mock from 'fixtures/api/pictures/5';
1010
import pictures5ImageableMock from 'fixtures/api/pictures/5/imageable';
1111

12+
import config from '../../config/environment';
13+
1214
module('Acceptance | polymorphic', {
1315
beforeEach: function() {
1416
this.sandbox = window.sinon.sandbox.create();
@@ -23,7 +25,7 @@ module('Acceptance | polymorphic', {
2325

2426
test('visiting /pictures list', function(assert) {
2527
assert.expect(6);
26-
setupFetchResonses(this.sandbox);
28+
setupFetchResponses(this.sandbox);
2729

2830
visit('/pictures');
2931
andThen(function() {
@@ -39,7 +41,7 @@ test('visiting /pictures list', function(assert) {
3941

4042
test('visiting /pictures/1, picture with an (imageable) product relation', function(assert) {
4143
assert.expect(3);
42-
setupFetchResonses(this.sandbox);
44+
setupFetchResponses(this.sandbox);
4345

4446
visit('/pictures/1');
4547
andThen(function() {
@@ -54,7 +56,7 @@ test('visiting /pictures/1, picture with an (imageable) product relation', funct
5456

5557
test('visiting /pictures/5, picture with an (imageable) employee relation', function(assert) {
5658
assert.expect(3);
57-
setupFetchResonses(this.sandbox);
59+
setupFetchResponses(this.sandbox);
5860

5961
visit('/pictures/5');
6062
andThen(function() {
@@ -68,27 +70,28 @@ test('visiting /pictures/5, picture with an (imageable) employee relation', func
6870
});
6971

7072

71-
function setupFetchResonses(sandbox) {
73+
function setupFetchResponses(sandbox) {
74+
const apiUrl = [config.APP.API_HOST, config.APP.API_PATH].join('/');
7275
sandbox.stub(window, 'fetch', function (url) {
7376
let resp;
7477
switch(url) {
75-
case 'api/v1/pictures?sort=id&include=imageable':
78+
case [apiUrl, 'pictures?sort=id&include=imageable'].join('/'):
7679
resp = picturesMockResponse();
7780
break;
78-
case 'api/v1/pictures/1':
81+
case [apiUrl, 'pictures/1'].join('/'):
7982
resp = pictures1MockResponse();
8083
break;
81-
case '/api/v1/pictures/1/imageable':
84+
case [apiUrl, 'pictures/1/imageable'].join('/'):
8285
resp = pictures1ImageableMockResponse();
8386
break;
84-
case 'api/v1/pictures/5':
87+
case [apiUrl, 'pictures/5'].join('/'):
8588
resp = pictures5MockResponse();
8689
break;
87-
case '/api/v1/pictures/5/imageable':
90+
case [apiUrl, 'pictures/5/imageable'].join('/'):
8891
resp = pictures5ImageableMockResponse();
8992
break;
9093
default:
91-
throw('no mocked fetch reponse for request');
94+
throw('no mocked fetch reponse for request: ' + url);
9295
}
9396
return resp;
9497
});

tests/dummy/app/adapters/author.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
import ApplicationAdapter from './application';
2-
import config from '../config/environment';
32

43
export default ApplicationAdapter.extend({
5-
type: 'author',
6-
7-
url: config.APP.API_PATH + '/authors',
8-
9-
fetchUrl: function(url) {
10-
const proxy = config.APP.API_HOST_PROXY;
11-
const host = config.APP.API_HOST;
12-
if (proxy && host) {
13-
url = url.replace(proxy, host);
14-
}
15-
return url;
16-
}
4+
type: 'author'
175
});
Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
import ApplicationAdapter from './application';
2-
import config from '../config/environment';
32

43
export default ApplicationAdapter.extend({
5-
type: 'comment',
6-
7-
url: config.APP.API_PATH + '/comments',
8-
9-
fetchUrl: function(url) {
10-
const proxy = config.APP.API_HOST_PROXY;
11-
const host = config.APP.API_HOST;
12-
if (proxy && host) {
13-
url = url.replace(proxy, host);
14-
}
15-
return url;
16-
}
4+
type: 'comment'
175
});
Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
import ApplicationAdapter from './application';
2-
import config from '../config/environment';
32

43
export default ApplicationAdapter.extend({
5-
type: 'commenter',
6-
7-
url: config.APP.API_PATH + '/commenters',
8-
9-
fetchUrl: function(url) {
10-
const proxy = config.APP.API_HOST_PROXY;
11-
const host = config.APP.API_HOST;
12-
if (proxy && host) {
13-
url = url.replace(proxy, host);
14-
}
15-
return url;
16-
}
4+
type: 'commenter'
175
});
Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
import ApplicationAdapter from './application';
2-
import config from '../config/environment';
32

43
export default ApplicationAdapter.extend({
5-
type: 'employee',
6-
7-
url: config.APP.API_PATH + '/employees',
8-
9-
fetchUrl: function(url) {
10-
const proxy = config.APP.API_HOST_PROXY;
11-
const host = config.APP.API_HOST;
12-
if (proxy && host) {
13-
url = url.replace(proxy, host);
14-
}
15-
return url;
16-
}
4+
type: 'employee'
175
});

tests/dummy/app/adapters/imageable.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,10 @@
11
import ApplicationAdapter from './application';
2-
import config from '../config/environment';
3-
//import { pluralize } from 'ember-inflector';
42

53
export default ApplicationAdapter.extend({
64
type: 'imageable',
75

86
url: null,
97

10-
fetchUrl: function(url) {
11-
const proxy = config.APP.API_HOST_PROXY;
12-
const host = config.APP.API_HOST;
13-
if (proxy && host) {
14-
url = url.replace(proxy, host);
15-
}
16-
return url;
17-
},
18-
198
find() {},
209
findOne() {},
2110
findQuery() {},
Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
import ApplicationAdapter from './application';
2-
import config from '../config/environment';
32

43
export default ApplicationAdapter.extend({
5-
type: 'picture',
6-
7-
url: config.APP.API_PATH + '/pictures',
8-
9-
fetchUrl: function(url) {
10-
const proxy = config.APP.API_HOST_PROXY;
11-
const host = config.APP.API_HOST;
12-
if (proxy && host) {
13-
url = url.replace(proxy, host);
14-
}
15-
return url;
16-
}
4+
type: 'picture'
175
});

0 commit comments

Comments
 (0)