Skip to content

Commit 96f55bd

Browse files
authored
Merge pull request #11 from platformsh/routes-utils
Add useful route filtering utilities
2 parents 58545e7 + 675978e commit 96f55bd

4 files changed

Lines changed: 259 additions & 85 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "platformsh-config",
3-
"version": "2.2.5",
3+
"version": "2.3.0",
44
"description": "Helper for running nodejs applications on Platform.sh",
55
"main": "lib/platformsh.js",
66
"keywords": [

src/platformsh.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,64 @@ class Config {
198198
return this.routesDef;
199199
}
200200

201+
/**
202+
* Returns the primary route.
203+
*
204+
* The primary route is the one marked primary in `routes.yaml`, or else
205+
* the first non-redirect route in that file if none are marked.
206+
*
207+
* @return {object}
208+
* The route definition. The generated URL of the route is added as a "url" key.
209+
*/
210+
getPrimaryRoute() {
211+
// eslint-disable-next-line no-unused-vars
212+
for (const [url, route] of Object.entries(this.routes())) {
213+
if (route.primary === true) {
214+
return route;
215+
}
216+
}
217+
218+
throw new Error(`No primary route found. This isn't supposed to happen.`);
219+
}
220+
221+
/**
222+
* Returns just those routes that point to a valid upstream.
223+
*
224+
* This method is similar to routes(), but filters out redirect routes that are rarely
225+
* useful for app configuration. If desired it can also filter to just those routes
226+
* whose upstream is a given application name. To retrieve routes that point to the
227+
* current application where the code is being run, use:
228+
*
229+
* routes = config.getUpstreamRoutes(config.applicationName);
230+
*
231+
* @param {string|null} appName
232+
* The name of the upstream app on which to filter, if any.
233+
* @return {object}
234+
* An object map of route definitions.
235+
*/
236+
getUpstreamRoutes(appName = null) {
237+
// Because routes is an object/dictionary, we can't just filter it directly.
238+
// Verbose way it is.
239+
240+
const routes = this.routes();
241+
const filter = route => {
242+
return route.type === 'upstream'
243+
// On Dedicated, the upstream name sometimes is `app:http` instead of just `app`.
244+
// If no name is specified then don't bother checking.
245+
&& (!appName || appName === route.upstream.split(':')[0]);
246+
};
247+
248+
let ret = {};
249+
250+
Object.keys(routes).forEach(function(key) {
251+
if (filter(routes[key])) {
252+
ret[key] = routes[key];
253+
}
254+
});
255+
256+
return ret;
257+
}
258+
201259
/**
202260
* Returns a single route definition.
203261
*

test/testdata/PLATFORM_ROUTES.json

Lines changed: 156 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,160 @@
11
{
2-
"https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
3-
"original_url" : "https://www.{default}/",
4-
"attributes" : {},
5-
"type" : "upstream",
6-
"restrict_robots" : false,
7-
"tls" : {
8-
"client_authentication" : null,
9-
"min_version" : 771,
10-
"client_certificate_authorities" : [],
11-
"strict_transport_security" : {
12-
"include_subdomains" : null,
13-
"enabled" : true,
14-
"preload" : null
15-
}
16-
},
17-
"upstream" : "app",
18-
"cache" : {
19-
"enabled" : true,
20-
"headers" : [
21-
"Accept",
22-
"Accept-Language"
23-
],
24-
"cookies" : [
25-
"/^SS?ESS.*/"
26-
],
27-
"default_ttl" : 0
28-
},
29-
"http_access" : {
30-
"addresses" : [],
31-
"basic_auth" : {}
32-
},
33-
"primary" : true,
34-
"id" : "main",
35-
"ssi" : {
36-
"enabled" : false
2+
"https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
3+
"original_url" : "https://www.{default}/",
4+
"attributes" : {},
5+
"type" : "upstream",
6+
"restrict_robots" : false,
7+
"tls" : {
8+
"client_authentication" : null,
9+
"min_version" : 771,
10+
"client_certificate_authorities" : [],
11+
"strict_transport_security" : {
12+
"include_subdomains" : null,
13+
"enabled" : true,
14+
"preload" : null
3715
}
38-
},
39-
"http://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
40-
"id" : null,
41-
"to" : "https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/",
42-
"primary" : false,
43-
"original_url" : "http://www.{default}/",
44-
"http_access" : {
45-
"basic_auth" : {},
46-
"addresses" : []
47-
},
48-
"restrict_robots" : false,
49-
"type" : "redirect"
50-
},
51-
"https://master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
52-
"id" : null,
53-
"to" : "https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/",
54-
"primary" : false,
55-
"http_access" : {
56-
"addresses" : [],
57-
"basic_auth" : {}
58-
},
59-
"tls" : {
60-
"client_authentication" : null,
61-
"min_version" : null,
62-
"strict_transport_security" : {
63-
"include_subdomains" : null,
64-
"enabled" : null,
65-
"preload" : null
66-
},
67-
"client_certificate_authorities" : []
68-
},
69-
"restrict_robots" : false,
70-
"type" : "redirect",
71-
"attributes" : {},
72-
"original_url" : "https://{default}/"
73-
},
74-
"http://master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
75-
"to" : "https://master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/",
76-
"id" : null,
77-
"primary" : false,
78-
"http_access" : {
79-
"addresses" : [],
80-
"basic_auth" : {}
16+
},
17+
"upstream" : "app",
18+
"cache" : {
19+
"enabled" : true,
20+
"headers" : [
21+
"Accept",
22+
"Accept-Language"
23+
],
24+
"cookies" : [
25+
"/^SS?ESS.*/"
26+
],
27+
"default_ttl" : 0
28+
},
29+
"http_access" : {
30+
"addresses" : [],
31+
"basic_auth" : {}
32+
},
33+
"primary" : true,
34+
"id" : "main",
35+
"ssi" : {
36+
"enabled" : false
37+
}
38+
},
39+
"https://www2.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
40+
"original_url" : "https://www.{default}/",
41+
"attributes" : {},
42+
"type" : "upstream",
43+
"restrict_robots" : false,
44+
"tls" : {
45+
"client_authentication" : null,
46+
"min_version" : 771,
47+
"client_certificate_authorities" : [],
48+
"strict_transport_security" : {
49+
"include_subdomains" : null,
50+
"enabled" : true,
51+
"preload" : null
52+
}
53+
},
54+
"upstream" : "app",
55+
"cache" : {
56+
"enabled" : true,
57+
"headers" : [
58+
"Accept",
59+
"Accept-Language"
60+
],
61+
"cookies" : [
62+
"/^SS?ESS.*/"
63+
],
64+
"default_ttl" : 0
65+
},
66+
"http_access" : {
67+
"addresses" : [],
68+
"basic_auth" : {}
69+
},
70+
"primary" : false,
71+
"id" : "main2",
72+
"ssi" : {
73+
"enabled" : false
74+
}
75+
},
76+
"https://www3.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
77+
"original_url" : "https://www.{default}/",
78+
"attributes" : {},
79+
"type" : "upstream",
80+
"restrict_robots" : false,
81+
"tls" : {
82+
"client_authentication" : null,
83+
"min_version" : 771,
84+
"client_certificate_authorities" : [],
85+
"strict_transport_security" : {
86+
"include_subdomains" : null,
87+
"enabled" : true,
88+
"preload" : null
89+
}
90+
},
91+
"upstream" : "app2",
92+
"cache" : {
93+
"enabled" : true,
94+
"headers" : [
95+
"Accept",
96+
"Accept-Language"
97+
],
98+
"cookies" : [
99+
"/^SS?ESS.*/"
100+
],
101+
"default_ttl" : 0
102+
},
103+
"http_access" : {
104+
"addresses" : [],
105+
"basic_auth" : {}
106+
},
107+
"primary" : false,
108+
"id" : "main3",
109+
"ssi" : {
110+
"enabled" : false
111+
}
112+
},
113+
"http://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
114+
"id" : null,
115+
"to" : "https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/",
116+
"primary" : false,
117+
"original_url" : "http://www.{default}/",
118+
"http_access" : {
119+
"basic_auth" : {},
120+
"addresses" : []
121+
},
122+
"restrict_robots" : false,
123+
"type" : "redirect"
124+
},
125+
"https://master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
126+
"id" : null,
127+
"to" : "https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/",
128+
"primary" : false,
129+
"http_access" : {
130+
"addresses" : [],
131+
"basic_auth" : {}
132+
},
133+
"tls" : {
134+
"client_authentication" : null,
135+
"min_version" : null,
136+
"strict_transport_security" : {
137+
"include_subdomains" : null,
138+
"enabled" : null,
139+
"preload" : null
81140
},
82-
"original_url" : "http://{default}/",
83-
"type" : "redirect",
84-
"restrict_robots" : false
85-
}
141+
"client_certificate_authorities" : []
142+
},
143+
"restrict_robots" : false,
144+
"type" : "redirect",
145+
"attributes" : {},
146+
"original_url" : "https://{default}/"
147+
},
148+
"http://master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/" : {
149+
"to" : "https://master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/",
150+
"id" : null,
151+
"primary" : false,
152+
"http_access" : {
153+
"addresses" : [],
154+
"basic_auth" : {}
155+
},
156+
"original_url" : "http://{default}/",
157+
"type" : "redirect",
158+
"restrict_robots" : false
159+
}
86160
}

test/tests.js

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ describe("Config tests", () => {
155155
let routes = c.routes();
156156

157157
assert.ok(typeof routes == 'object');
158-
assert.equal(Object.keys(routes).length, 4);
158+
assert.equal(Object.keys(routes).length, 6);
159159
});
160160

161161
it('throws when loading routes in build time', () => {
@@ -166,6 +166,48 @@ describe("Config tests", () => {
166166
});
167167
});
168168

169+
it('gets the primary route', () => {
170+
let c = new psh.Config(mockEnvironmentRuntime);
171+
172+
let route = c.getPrimaryRoute();
173+
174+
assert.equal(route['original_url'], 'https://www.{default}/');
175+
assert.equal(route['primary'], true);
176+
});
177+
178+
it('returns all upstream routes', () => {
179+
let c = new psh.Config(mockEnvironmentRuntime);
180+
181+
let routes = c.getUpstreamRoutes();
182+
183+
assert.equal(3, Object.keys(routes).length);
184+
assert.equal(routes['https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/']['original_url'], 'https://www.{default}/');
185+
});
186+
187+
it('returns all upstream routes for a specific app', () => {
188+
let c = new psh.Config(mockEnvironmentRuntime);
189+
190+
let routes = c.getUpstreamRoutes('app');
191+
192+
assert.equal(2, Object.keys(routes).length);
193+
assert.equal(routes['https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/']['original_url'], 'https://www.{default}/');
194+
});
195+
196+
it('returns all upstream routes for a specific app on dedicated', () => {
197+
let env = mockEnvironmentRuntime;
198+
// Simulate a Dedicated-style upstream name.
199+
let routeData = loadJsonFile('PLATFORM_ROUTES');
200+
routeData['https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/']['upstream'] = 'app:http';
201+
env['PLATFORM_ROUTES'] = encode(routeData);
202+
203+
let c = new psh.Config(env);
204+
205+
let routes = c.getUpstreamRoutes('app');
206+
207+
assert.equal(2, Object.keys(routes).length);
208+
assert.equal(routes['https://www.master-7rqtwti-gcpjkefjk4wc2.us-2.platformsh.site/']['original_url'], 'https://www.{default}/');
209+
});
210+
169211
it('gets a route by id', () => {
170212
let c = new psh.Config(mockEnvironmentRuntime);
171213

@@ -193,7 +235,7 @@ describe("Config tests", () => {
193235
let routes = c.routes();
194236

195237
assert.ok(typeof routes == 'object');
196-
assert.equal(Object.keys(routes).length, 4);
238+
assert.equal(Object.keys(routes).length, 6);
197239
});
198240
});
199241

0 commit comments

Comments
 (0)