-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Request based constraints implementation #166
Changes from 21 commits
f19a0db
1220b07
5544329
ab39b39
b311ec0
141f42f
25f7b04
c6b11d7
eede77e
9db137b
ac61bde
9c3d4d8
fe27b59
212c3ae
8650a7c
edd00c9
edde841
537b684
c05c763
b9954dc
303f2f3
4aa5990
c5ea6e2
2ac7cba
40a3c92
a1bf496
1c49cac
6abe279
35e9da8
65bfdcf
ce44dcb
0e04077
8c66309
ce0260d
7d7e0f2
52a3479
df674d0
f809308
159d941
6f83041
bf4a5e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
'use strict' | ||
|
||
const ConstraintsStore = require('./constraints-store') | ||
|
||
const acceptVersionStrategy = require('./strategies/accept-version') | ||
const acceptHostStrategy = require('./strategies/accept-host') | ||
|
||
const DEFAULT_STRATEGIES_NAMES = ['version', 'host'] | ||
|
||
module.exports = (customStrategies) => { | ||
const strategies = [ | ||
new acceptVersionStrategy(), | ||
new acceptHostStrategy() | ||
] | ||
|
||
if (customStrategies) { | ||
for (let i = 0; i < customStrategies.length; i++) { | ||
const strategy = new customStrategies[i]() | ||
if (DEFAULT_STRATEGIES_NAMES.indexOf(strategy.name) !== -1) { | ||
strategies[i] = strategy | ||
} else { | ||
strategies.push(strategy) | ||
} | ||
} | ||
} | ||
|
||
return { | ||
storage: function () { | ||
const stores = {} | ||
for (var i = 0; i < strategies.length; i++) { | ||
stores[strategies[i].name] = strategies[i].storage() | ||
} | ||
return ConstraintsStore(stores) | ||
}, | ||
deriveConstraints: function (req, ctx) { | ||
const derivedConstraints = {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is no longer a super hot path and only gets invoked once per route match, right? Maybe not worth it, but if you wanted to be really fancy, you could set up this object's prototype outside this object literal with the early-prototype-definition trick Fastify uses elsewhere and that you mentioned in a comment. module.exports = (customStrategies) => {
const strategies = [
new acceptVersionStrategy(),
new acceptHostStrategy()
]
if (customStrategies) {
for (let i = 0; i < customStrategies.length; i++) {
const strategy = new customStrategies[i]()
if (DEFAULT_STRATEGIES_NAMES.indexOf(strategy.name) !== -1) {
strategies[i] = strategy
} else {
strategies.push(strategy)
}
}
}
// Bang out a full prototype ahead of time
const derivedConstraintsPrototype = class {};
for (const strategy of strategies) {
derivedConstraintsPrototype.prototype[strategy.name] = null
}
return {
storage: function () {
const stores = {}
for (var i = 0; i < strategies.length; i++) {
stores[strategies[i].name] = strategies[i].storage()
}
return ConstraintsStore(stores)
},
deriveConstraints: function (req, ctx) {
const derivedConstraints = new derivedConstraintsPrototype()
let value, hasConstraint = false
for (var i = 0; i < strategies.length; i++) {
value = strategies[i].deriveConstraint(req, ctx)
if (value) {
hasConstraint = true
derivedConstraints[strategies[i].name] = value
}
}
return hasConstraint ? derivedConstraints : null
}
}
} |
||
let value, hasConstraint = false | ||
for (var i = 0; i < strategies.length; i++) { | ||
value = strategies[i].deriveConstraint(req, ctx) | ||
if (value) { | ||
hasConstraint = true | ||
derivedConstraints[strategies[i].name] = value | ||
} | ||
} | ||
|
||
return hasConstraint ? derivedConstraints : null | ||
} | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
'use strict' | ||
|
||
const assert = require('assert') | ||
|
||
function ConstraintsStore (stores) { | ||
if (!(this instanceof ConstraintsStore)) { | ||
return new ConstraintsStore(stores) | ||
} | ||
this.storeIdCounter = 1 | ||
this.stores = stores | ||
this.storeMap = new Map() | ||
} | ||
|
||
ConstraintsStore.prototype.set = function (constraints, store) { | ||
// TODO: Should I check for existence of at least one constraint? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, thanks |
||
if (typeof constraints !== 'object' || constraints === null) { | ||
throw new TypeError('Constraints should be an object') | ||
} | ||
|
||
const storeId = this.storeIdCounter++ | ||
this.storeMap.set(storeId, store) | ||
|
||
var kConstraint | ||
const kConstraints = Object.keys(constraints) | ||
for (var i = 0; i < kConstraints.length; i++) { | ||
kConstraint = kConstraints[i] | ||
assert(this.stores[kConstraint] !== null, `No strategy available for handling the constraint '${kConstraint}'`) | ||
this.stores[kConstraint].set(constraints[kConstraint], storeId) | ||
} | ||
|
||
return this | ||
} | ||
|
||
ConstraintsStore.prototype.get = function (constraints, method) { | ||
if (typeof constraints !== 'object' || constraints === null) { | ||
throw new TypeError('Constraints should be an object') | ||
} | ||
|
||
var tmpStoreId, storeId | ||
const kConstraints = Object.keys(constraints) | ||
for (var i = 0; i < kConstraints.length; i++) { | ||
const kConstraint = kConstraints[i] | ||
assert(this.stores[kConstraint] !== null, `No strategy available for handling the constraint '${kConstraint}'`) | ||
tmpStoreId = this.stores[kConstraint].get(constraints[kConstraint]) | ||
if (!tmpStoreId || (storeId && tmpStoreId !== storeId)) return null | ||
else storeId = tmpStoreId | ||
} | ||
|
||
if (storeId) { | ||
const store = this.storeMap.get(storeId) | ||
if (store && store[method]) return store | ||
} | ||
|
||
return null | ||
} | ||
|
||
module.exports = ConstraintsStore |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use strict' | ||
|
||
// TODO: Add regex support | ||
function acceptHost() {} | ||
|
||
function HostStore() { | ||
let hosts = {} | ||
return { | ||
get: (host) => { return hosts[host] || null }, | ||
set: (host, store) => { hosts[host] = store }, | ||
del: (host) => { delete hosts[host] }, | ||
empty: () => { hosts = {} } | ||
} | ||
} | ||
|
||
acceptHost.prototype.name = 'host' | ||
acceptHost.prototype.storage = HostStore | ||
acceptHost.prototype.deriveConstraint = function (req, ctx) { | ||
return req.headers['host'] | ||
} | ||
|
||
module.exports = acceptHost |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant should the validation code check the properties inside
opts.constraints
and make sure there are strategies to handle each one of them?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please, thanks.