diff --git a/README.md b/README.md index 1c7c51e..72de787 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Constraints can be combined, and route handlers will only match if __all__ of th ### Custom Constraint Strategies -Custom constraining strategies can be added and are matched against incoming requests while trying to maintain `find-my-way`'s high performance. To register a new type of constraint, you must add a new constraint strategy that knows how to match values to handlers, and that knows how to get the constraint value from a request. Register strategies when constructing a router or use the addCustomConstraintStrategy method. +Custom constraining strategies can be added and are matched against incoming requests while trying to maintain `find-my-way`'s high performance. To register a new type of constraint, you must add a new constraint strategy that knows how to match values to handlers, and that knows how to get the constraint value from a request. Register strategies when constructing a router or use the addConstraintStrategy method. Add a custom constrain strategy when constructing a router: @@ -192,7 +192,7 @@ const customResponseTypeStrategy = { const router = FindMyWay({ constraints: { accept: customResponseTypeStrategy } }); ``` -Add a custom constraint strategy using the addCustomConstraintStrategy method: +Add a custom constraint strategy using the addConstraintStrategy method: ```js const customResponseTypeStrategy = { @@ -215,7 +215,7 @@ const customResponseTypeStrategy = { } const router = FindMyWay(); -router.addCustomConstraintStrategy(customResponseTypeStrategy); +router.addConstraintStrategy(customResponseTypeStrategy); ``` Once a custom constraint strategy is registered, routes can be added that are constrained using it: diff --git a/index.d.ts b/index.d.ts index 7f01d53..ccb439d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -161,8 +161,8 @@ declare namespace Router { prettyPrint(): string; prettyPrint(opts: { commonPrefix?: boolean, includeMeta?: boolean | (string | symbol)[] }): string; - hasCustomConstraintStrategy(strategyName: string): boolean; - addCustomConstraintStrategy(constraintStrategy: ConstraintStrategy): void; + hasConstraintStrategy(strategyName: string): boolean; + addConstraintStrategy(constraintStrategy: ConstraintStrategy): void; all: ShortHandRoute; diff --git a/index.js b/index.js index 1aad974..654fabd 100644 --- a/index.js +++ b/index.js @@ -266,12 +266,12 @@ Router.prototype._on = function _on (method, path, opts, handler, store) { currentNode.handlerStorage.addHandler(handler, params, store, this.constrainer, constraints) } -Router.prototype.hasCustomConstraintStrategy = function (strategyName) { - return this.constrainer.hasCustomConstraintStrategy(strategyName) +Router.prototype.hasConstraintStrategy = function (strategyName) { + return this.constrainer.hasConstraintStrategy(strategyName) } -Router.prototype.addCustomConstraintStrategy = function (constraints) { - this.constrainer.addCustomConstraintStrategy(constraints) +Router.prototype.addConstraintStrategy = function (constraints) { + this.constrainer.addConstraintStrategy(constraints) this._rebuild(this.routes) } diff --git a/lib/constrainer.js b/lib/constrainer.js index 79f84c0..947fe3d 100644 --- a/lib/constrainer.js +++ b/lib/constrainer.js @@ -16,27 +16,30 @@ class Constrainer { // validate and optimize prototypes of given custom strategies if (customStrategies) { for (const strategy of Object.values(customStrategies)) { - this.addCustomConstraintStrategy(strategy) + this.addConstraintStrategy(strategy) } } } - hasCustomConstraintStrategy (strategyName) { + hasConstraintStrategy (strategyName) { const customConstraintStrategy = this.strategies[strategyName] - return customConstraintStrategy !== undefined && customConstraintStrategy.isCustom === true + if (customConstraintStrategy !== undefined) { + return customConstraintStrategy.isCustom || this.strategiesInUse.has(strategyName) + } + return false } - addCustomConstraintStrategy (strategy) { + addConstraintStrategy (strategy) { assert(typeof strategy.name === 'string' && strategy.name !== '', 'strategy.name is required.') assert(strategy.storage && typeof strategy.storage === 'function', 'strategy.storage function is required.') assert(strategy.deriveConstraint && typeof strategy.deriveConstraint === 'function', 'strategy.deriveConstraint function is required.') - if (this.hasCustomConstraintStrategy(strategy.name)) { - throw new Error(`There is already exists a custom constraint with the name ${strategy.name}.`) + if (this.strategies[strategy.name] && this.strategies[strategy.name].isCustom) { + throw new Error(`There already exists a custom constraint with the name ${strategy.name}.`) } if (this.strategiesInUse.has(strategy.name)) { - throw new Error(`There is already exists a route with ${strategy.name} constraint.`) + throw new Error(`There already exists a route with ${strategy.name} constraint.`) } strategy.isCustom = true diff --git a/test/constraint.custom-versioning.test.js b/test/constraint.custom-versioning.test.js index 67caf4a..e5559c1 100644 --- a/test/constraint.custom-versioning.test.js +++ b/test/constraint.custom-versioning.test.js @@ -42,7 +42,7 @@ test('A route could support multiple versions (find) / 1 (add strategy outside c const findMyWay = FindMyWay() - findMyWay.addCustomConstraintStrategy(customVersioning) + findMyWay.addConstraintStrategy(customVersioning) findMyWay.on('GET', '/', { constraints: { version: 'application/vnd.example.api+json;version=2' } }, noop) findMyWay.on('GET', '/', { constraints: { version: 'application/vnd.example.api+json;version=3' } }, noop) @@ -84,7 +84,7 @@ test('Overriding default strategies uses the custom deriveConstraint function (a const findMyWay = FindMyWay() - findMyWay.addCustomConstraintStrategy(customVersioning) + findMyWay.addConstraintStrategy(customVersioning) findMyWay.on('GET', '/', { constraints: { version: 'application/vnd.example.api+json;version=2' } }, (req, res, params) => { t.equal(req.headers.accept, 'application/vnd.example.api+json;version=2') @@ -111,9 +111,21 @@ test('Overriding custom strategies throws as error (add strategy outside constru const findMyWay = FindMyWay() - findMyWay.addCustomConstraintStrategy(customVersioning) + findMyWay.addConstraintStrategy(customVersioning) - t.throws(() => findMyWay.addCustomConstraintStrategy(customVersioning), - 'There is already exists a custom constraint with the name version.' + t.throws(() => findMyWay.addConstraintStrategy(customVersioning), + 'There already exists a custom constraint with the name version.' + ) +}) + +test('Overriding default strategies after defining a route with constraint', t => { + t.plan(1) + + const findMyWay = FindMyWay() + + findMyWay.on('GET', '/', { constraints: { host: 'fastify.io', version: '1.0.0' } }, () => {}) + + t.throws(() => findMyWay.addConstraintStrategy(customVersioning), + 'There already exists a route with version constraint.' ) }) diff --git a/test/constraint.custom.test.js b/test/constraint.custom.test.js index 9a0567f..f5e757d 100644 --- a/test/constraint.custom.test.js +++ b/test/constraint.custom.test.js @@ -42,7 +42,7 @@ test('A route could support a custom constraint strategy (add strategy outside c const findMyWay = FindMyWay() - findMyWay.addCustomConstraintStrategy(customHeaderConstraint) + findMyWay.addConstraintStrategy(customHeaderConstraint) findMyWay.on('GET', '/', { constraints: { requestedBy: 'curl' } }, alpha) findMyWay.on('GET', '/', { constraints: { requestedBy: 'wget' } }, beta) @@ -79,7 +79,7 @@ test('A route could support a custom constraint strategy while versioned (add st const findMyWay = FindMyWay() - findMyWay.addCustomConstraintStrategy(customHeaderConstraint) + findMyWay.addConstraintStrategy(customHeaderConstraint) findMyWay.on('GET', '/', { constraints: { requestedBy: 'curl', version: '1.0.0' } }, alpha) findMyWay.on('GET', '/', { constraints: { requestedBy: 'curl', version: '2.0.0' } }, beta) @@ -124,7 +124,7 @@ test('A route could support a custom constraint strategy while versioned and hos const findMyWay = FindMyWay() - findMyWay.addCustomConstraintStrategy(customHeaderConstraint) + findMyWay.addConstraintStrategy(customHeaderConstraint) findMyWay.on('GET', '/', { constraints: { requestedBy: 'curl', version: '1.0.0', host: 'fastify.io' } }, alpha) findMyWay.on('GET', '/', { constraints: { requestedBy: 'curl', version: '2.0.0', host: 'fastify.io' } }, beta) @@ -171,7 +171,7 @@ test('Custom constraint strategies can set mustMatchWhenDerived flag to true whi } }) - findMyWay.addCustomConstraintStrategy({ + findMyWay.addConstraintStrategy({ ...customHeaderConstraint, mustMatchWhenDerived: true }) @@ -212,7 +212,7 @@ test('Custom constraint strategies can set mustMatchWhenDerived flag to true whi } }) - findMyWay.addCustomConstraintStrategy({ + findMyWay.addConstraintStrategy({ ...customHeaderConstraint, mustMatchWhenDerived: true }) @@ -253,7 +253,7 @@ test('Custom constraint strategies can set mustMatchWhenDerived flag to false wh } }) - findMyWay.addCustomConstraintStrategy({ + findMyWay.addConstraintStrategy({ ...customHeaderConstraint, mustMatchWhenDerived: true }) @@ -264,14 +264,11 @@ test('Custom constraint strategies can set mustMatchWhenDerived flag to false wh }) test('Has constraint strategy method test', t => { - t.plan(1) + t.plan(2) - const findMyWay = FindMyWay({ - defaultRoute (req, res) { - t.pass() - } - }) + const findMyWay = FindMyWay() - findMyWay.addCustomConstraintStrategy(customHeaderConstraint) - t.same(findMyWay.hasCustomConstraintStrategy(customHeaderConstraint.name), true) + t.same(findMyWay.hasConstraintStrategy(customHeaderConstraint.name), false) + findMyWay.addConstraintStrategy(customHeaderConstraint) + t.same(findMyWay.hasConstraintStrategy(customHeaderConstraint.name), true) }) diff --git a/test/constraints.test.js b/test/constraints.test.js index 85cdad2..13124fc 100644 --- a/test/constraints.test.js +++ b/test/constraints.test.js @@ -90,10 +90,20 @@ test('Routes with multiple constraints are matched before routes with one constr }) test('Has constraint strategy method test', t => { - t.plan(2) + t.plan(6) const findMyWay = FindMyWay() - t.same(findMyWay.hasCustomConstraintStrategy('version'), false) - t.same(findMyWay.hasCustomConstraintStrategy('host'), false) + t.same(findMyWay.hasConstraintStrategy('version'), false) + t.same(findMyWay.hasConstraintStrategy('host'), false) + + findMyWay.on('GET', '/', { constraints: { host: 'fastify.io' } }, () => {}) + + t.same(findMyWay.hasConstraintStrategy('version'), false) + t.same(findMyWay.hasConstraintStrategy('host'), true) + + findMyWay.on('GET', '/', { constraints: { host: 'fastify.io', version: '1.0.0' } }, () => {}) + + t.same(findMyWay.hasConstraintStrategy('version'), true) + t.same(findMyWay.hasConstraintStrategy('host'), true) }) diff --git a/test/types/router.test-d.ts b/test/types/router.test-d.ts index e6ce153..43b6fdb 100644 --- a/test/types/router.test-d.ts +++ b/test/types/router.test-d.ts @@ -101,7 +101,7 @@ let http2Res!: Http2ServerResponse; expectType(router.on('GET', '/', () => {}, {})) expectType(router.on('GET', '/', { constraints: { version: '1.0.0' }}, () => {}, {})) - expectType(router.addCustomConstraintStrategy(constraints.foo)) + expectType(router.addConstraintStrategy(constraints.foo)) expectType(router.get('/', () => {})) expectType(router.get('/', { constraints: { version: '1.0.0' }}, () => {}))