-
Notifications
You must be signed in to change notification settings - Fork 115
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
Automatically add OPTIONS action #59
Changes from all commits
16fc51b
2482c26
2cc8273
75317d5
5d0b8b8
c2bfae2
8377979
4db7047
7b09ebb
a609094
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,41 @@ | ||
{ | ||
"name": "", | ||
"description": "", | ||
"method": "OPTIONS", | ||
"parameters": [], | ||
"attributes": { | ||
"relation": "", | ||
"uriTemplate": "" | ||
}, | ||
"content": [], | ||
"examples": [ | ||
{ | ||
"name": "", | ||
"description": "", | ||
"requests": [], | ||
"responses": [ | ||
{ | ||
"name": "200", | ||
"description": "", | ||
"headers": [ | ||
{ | ||
"name": "Content-Type", | ||
"value": "text/plain" | ||
} | ||
], | ||
"body": "", | ||
"schema": "", | ||
"content": [ | ||
{ | ||
"element": "asset", | ||
"attributes": { | ||
"role": "bodyExample" | ||
}, | ||
"content": "" | ||
} | ||
] | ||
} | ||
] | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,12 +3,15 @@ var fs = require('fs'); | |
var protagonist = require('protagonist'); | ||
var async = require('async'); | ||
var pathToRegexp = require('path-to-regexp'); | ||
var _ = require('lodash'); | ||
|
||
var urlParser = require('../url-parser'); | ||
var route = require('../route'); | ||
var queryComparator = require('../query-comparator'); | ||
|
||
var ROUTE_MAP = null; | ||
var autoOptions; | ||
var autoOptionsAction = require('../json/auto-options-action.json'); | ||
|
||
var parseAction = function(uriTemplate, action) { | ||
var parsedUrl = urlParser.parse(uriTemplate); | ||
|
@@ -32,14 +35,53 @@ var parseBlueprint = function(filePath) { | |
return; | ||
} | ||
|
||
var allRoutesList = []; | ||
result.ast.resourceGroups.forEach(function(resourceGroup){ | ||
resourceGroup.resources.forEach(function(resource){ | ||
resource.actions.forEach(function(action){ | ||
parseAction(resource.uriTemplate, action); | ||
saveRouteToTheList(resource, action); | ||
}); | ||
}); | ||
}); | ||
|
||
// add OPTIONS route where its missing - this must be done after all routes are parsed | ||
if (autoOptions) { | ||
addOptionsRoutesWhereMissing(allRoutesList); | ||
} | ||
|
||
cb(); | ||
|
||
/** | ||
* Adds route and its action to the allRoutesList. It appends the action when route already exists in the list. | ||
* @param resource Route URI | ||
* @param action HTTP action | ||
*/ | ||
function saveRouteToTheList(resource, action) { | ||
// used to add options routes later | ||
if (typeof allRoutesList[resource.uriTemplate] === 'undefined') { | ||
allRoutesList[resource.uriTemplate] = []; | ||
} | ||
allRoutesList[resource.uriTemplate].push(action); | ||
} | ||
|
||
function addOptionsRoutesWhereMissing(allRoutes) { | ||
var routesWithoutOptions = []; | ||
// extracts only routes without OPTIONS | ||
_.forIn(allRoutes, function (actions, route) { | ||
var containsOptions = _.reduce(actions, function (previousResult, iteratedAction) { | ||
return previousResult || (iteratedAction.method === 'OPTIONS'); | ||
}, false); | ||
if (containsOptions === false) { | ||
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. Would prefer to just test variable for falseyness, i.e. |
||
routesWithoutOptions.push(route); | ||
} | ||
}); | ||
|
||
_.forEach(routesWithoutOptions, function (uriTemplate) { | ||
// adds prepared OPTIONS action for route | ||
parseAction(uriTemplate, autoOptionsAction); | ||
}); | ||
} | ||
}); | ||
}; | ||
}; | ||
|
@@ -65,7 +107,9 @@ var setup = function(sourceFiles, cb) { | |
|
||
}; | ||
|
||
module.exports = function(sourceFiles, cb) { | ||
module.exports = function(options, cb) { | ||
var sourceFiles = options.sourceFiles; | ||
autoOptions = options.autoOptions; | ||
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. Could we just declare 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. I am not sure what is proper way to do this. Imho blueprint parser should be pulled out of route handler because its a different concern. This way routes are registered during parsing process. I feel that the list of routes/actions should be a result of parsing and we should register them after. This is why autoOptions flag is in global scope so I don't mess function parameters. I will refactor it and let you review it :-) 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. Yep agree totally about moving the parsing out, that's definitely something we have on our "roadmap". We want to eventually be able to modify routes at runtime. |
||
var middleware = function(req, res, next) { | ||
var handlers = null; | ||
Object.keys(ROUTE_MAP).forEach(function(urlPattern) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
var helper = require('../lib'); | ||
var request = helper.getRequest(); | ||
|
||
describe('Auto OPTIONS', function () { | ||
|
||
before(function (done) { | ||
helper.drakov.run({sourceFiles: 'test/example/md/simple-api.md', autoOptions: true}, done); | ||
}); | ||
|
||
after(function (done) { | ||
helper.drakov.stop(done); | ||
}); | ||
|
||
it('should respond for OPTIONS despite its not defined in api blueprint', function (done) { | ||
request.options('/api/things/2') | ||
.expect(200) | ||
.expect('Access-Control-Allow-Origin', '*') | ||
.end(helper.endCb(done)); | ||
}); | ||
|
||
it('should not override OPTIONS route specified in api blueprint', function (done) { | ||
request.options('/api/things') | ||
.expect(200) | ||
.expect('Access-Control-Allow-Origin', 'custom-domain.com') | ||
.end(helper.endCb(done)); | ||
}); | ||
|
||
it('should not respond for OPTIONS for paths missing in api blueprint', function (done) { | ||
request.options('/fjselifjsleifjselij') | ||
.expect(404) | ||
.end(helper.endCb(done)); | ||
}); | ||
|
||
}); |
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.
Huge thank you for updating the README 👍 🎱