Skip to content

Commit

Permalink
fix: switch to org/site
Browse files Browse the repository at this point in the history
  • Loading branch information
dylandepass committed Oct 15, 2024
1 parent 21ad084 commit 44853a8
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 40 deletions.
27 changes: 20 additions & 7 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
* governing permissions and limitations under the License.
*/

import { errorWithResponse } from './util.js';

/**
* @param {string[]} patterns
* @param {string} path
Expand Down Expand Up @@ -43,13 +45,25 @@ function extractPathParams(pattern, path) {
* @param {Partial<Config>} [overrides={}]
* @returns {Promise<Config|null>}
*/
export async function resolveConfig(ctx, tenant, overrides = {}) {
const confMap = await ctx.env.CONFIGS.get(tenant, 'json');
export async function resolveConfig(ctx, overrides = {}) {
const [_, org, site, route] = ctx.url.pathname.split('/');
if (!org) {
throw errorWithResponse(404, 'missing org');
}
if (!site) {
throw errorWithResponse(404, 'missing site');
}
if (!route) {
throw errorWithResponse(404, 'missing route');
}

const siteKey = `${org}--${site}`;
const confMap = await ctx.env.CONFIGS.get(siteKey, 'json');
if (!confMap) {
return null;
}
if (typeof confMap !== 'object') {
ctx.log.warn('invalid config for tenant', tenant);
ctx.log.warn('invalid config for', siteKey);
return null;
}

Expand All @@ -60,8 +74,6 @@ export async function resolveConfig(ctx, tenant, overrides = {}) {
suffix,
);

const [org, repo] = tenant.split('--');

// merge configs
/** @type {Config} */
const resolved = {
Expand All @@ -82,13 +94,14 @@ export async function resolveConfig(ctx, tenant, overrides = {}) {
params: {},
}),
org,
repo,
site,
route,
...overrides,
};
// ensure validity
// TODO: make this more robust
if (!resolved.pageType) {
ctx.log.warn('invalid config for tenant (missing pageType)', tenant);
ctx.log.warn('invalid config for tenant site (missing pageType)', siteKey);
return null;
}

Expand Down
12 changes: 2 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,23 +225,15 @@ export default {
return errorResponse(405, 'method not allowed');
}

const [_, tenant, route] = ctx.url.pathname.split('/');
if (!tenant) {
return errorResponse(404, 'missing tenant');
}
if (!route) {
return errorResponse(404, 'missing route');
}

try {
const overrides = Object.fromEntries(ctx.url.searchParams.entries());
const config = await resolveConfig(ctx, tenant, overrides);
const config = await resolveConfig(ctx, overrides);
console.debug('resolved config: ', JSON.stringify(config));
if (!config) {
return errorResponse(404, 'config not found');
}

return handlers[route](ctx, config);
return handlers[config.route](ctx, config);
} catch (e) {
if (e.response) {
return e.response;
Expand Down
3 changes: 3 additions & 0 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import type { ExecutionContext, KVNamespace } from "@cloudflare/workers-types/ex

declare global {
export interface Config {
org: string;
site: string;
route: string;
pageType: 'product' | string;
origin?: string;
apiKey: string;
Expand Down
100 changes: 77 additions & 23 deletions test/config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,39 @@ import { resolveConfig } from '../src/config.js';
/**
* @param {string} path
* @param {Record<string, Config>} configMap
* @param {string} [baseUrl='https://www.example.com/org/site/content']
* @returns {Context}
*/
const TEST_CONTEXT = (path, configMap) => ({
const TEST_CONTEXT = (path, configMap, baseUrl = 'https://www.example.com/org/site/content') => ({
env: {
CONFIGS: {
get: async (tenant) => configMap[tenant],
},
},
log: console,
url: new URL(`https://www.example.com/org--repo/content${path}`),
url: new URL(`${baseUrl}${path}`),
info: {
method: 'GET',
headers: {},
},
});

const defaultTenantConfigs = {
'org--site': {
base: {
apiKey: 'bad',
},
'/us/p/{{urlkey}}/{{sku}}': {
pageType: 'product',
apiKey: 'good',
},
},
};

describe('config tests', () => {
it('should extract path params', async () => {
const tenantConfigs = {
'org--repo': {
'org--site': {
base: {
apiKey: 'bad',
},
Expand All @@ -45,23 +58,21 @@ describe('config tests', () => {
},
},
};
const config = await resolveConfig(
TEST_CONTEXT('/us/p/my-url-key/some-sku', tenantConfigs),
'org--repo',
);
const config = await resolveConfig(TEST_CONTEXT('/us/p/my-url-key/some-sku', tenantConfigs));
assert.deepStrictEqual(config, {
apiKey: 'good',
params: { urlkey: 'my-url-key', sku: 'some-sku' },
headers: {},
pageType: 'product',
org: 'org',
repo: 'repo',
site: 'site',
route: 'content',
});
});

it('should combine headers objects', async () => {
const tenantConfigs = {
'org--repo': {
'org--site': {
base: {
apiKey: 'bad',
headers: {
Expand All @@ -79,23 +90,21 @@ describe('config tests', () => {
},
},
};
const config = await resolveConfig(
TEST_CONTEXT('/us/p/my-url-key/some-sku', tenantConfigs),
'org--repo',
);
const config = await resolveConfig(TEST_CONTEXT('/us/p/my-url-key/some-sku', tenantConfigs));
assert.deepStrictEqual(config, {
apiKey: 'good',
params: { urlkey: 'my-url-key', sku: 'some-sku' },
headers: { foo: '2', baz: '1', bar: '2' },
pageType: 'product',
org: 'org',
repo: 'repo',
site: 'site',
route: 'content',
});
});

it('should allow wildcard path segments', async () => {
const tenantConfigs = {
'org--repo': {
'org--site': {
base: {
apiKey: 'bad',
},
Expand All @@ -105,23 +114,21 @@ describe('config tests', () => {
},
},
};
const config = await resolveConfig(
TEST_CONTEXT('/us/p/something-here/some-sku', tenantConfigs),
'org--repo',
);
const config = await resolveConfig(TEST_CONTEXT('/us/p/something-here/some-sku', tenantConfigs));
assert.deepStrictEqual(config, {
apiKey: 'good',
params: { sku: 'some-sku' },
headers: {},
pageType: 'product',
org: 'org',
repo: 'repo',
site: 'site',
route: 'content',
});
});

it('should allow overrides', async () => {
const tenantConfigs = {
'org--repo': {
'org--site': {
base: {
apiKey: 'bad1',
},
Expand All @@ -133,7 +140,6 @@ describe('config tests', () => {
};
const config = await resolveConfig(
TEST_CONTEXT('/us/p/some-sku', tenantConfigs),
'org--repo',
{ apiKey: 'good' },
);
assert.deepStrictEqual(config, {
Expand All @@ -142,7 +148,55 @@ describe('config tests', () => {
pageType: 'product',
headers: {},
org: 'org',
repo: 'repo',
site: 'site',
route: 'content',
});
});

it('should throw if org is missing', async () => {
await assert.rejects(
resolveConfig(TEST_CONTEXT('', defaultTenantConfigs, 'http://www.example.com')),
new Error('missing org'),
);
});

it('should throw if site is missing', async () => {
await assert.rejects(
resolveConfig(TEST_CONTEXT('', defaultTenantConfigs, 'http://www.example.com/org')),
new Error('missing site'),
);
});

it('should throw if route is missing', async () => {
await assert.rejects(
resolveConfig(TEST_CONTEXT('', defaultTenantConfigs, 'http://www.example.com/org/site')),
new Error('missing route'),
);
});

it('should return null for invalid config', async () => {
const config = await resolveConfig(TEST_CONTEXT('/us/p/some-sku', {}));
assert.deepStrictEqual(config, null);
});

it('should return null if config is not an object', async () => {
const ctx = TEST_CONTEXT('/us/p/some-sku', {});
ctx.env.CONFIGS.get = async () => 'not an object';
const config = await resolveConfig(ctx);
assert.deepStrictEqual(config, null);
});

it('should log a warning if pageType is missing', async () => {
const tenantConfigs = {
'org--site': {
base: {
apiKey: 'good',
},
'/us/p/{{sku}}': {},
},
};
const ctx = TEST_CONTEXT('/us/p/some-sku', tenantConfigs);
const config = await resolveConfig(ctx);
assert.deepStrictEqual(config, null);
});
});

0 comments on commit 44853a8

Please sign in to comment.