Throw 405 - Method not allowed for api routes

closes #2757
- New error MethodNotAllowed
- Throw 405 if valid path but invalid method is used is apiRouter
- Adds api base tests
This commit is contained in:
Fabian Becker 2014-09-23 08:23:10 +00:00 committed by Hannah Wolfe
parent 177cdf1eb1
commit b15f1daf5a
4 changed files with 91 additions and 2 deletions

View File

@ -9,6 +9,7 @@ var _ = require('lodash'),
BadRequestError = require('./bad-request-error'),
InternalServerError = require('./internal-server-error'),
NoPermissionError = require('./no-permission-error'),
MethodNotAllowedError = require('./method-not-allowed-error'),
RequestEntityTooLargeError = require('./request-too-large-error'),
UnauthorizedError = require('./unauthorized-error'),
ValidationError = require('./validation-error'),
@ -359,3 +360,4 @@ module.exports.RequestEntityTooLargeError = RequestEntityTooLargeError;
module.exports.UnsupportedMediaTypeError = UnsupportedMediaTypeError;
module.exports.EmailError = EmailError;
module.exports.DataImportError = DataImportError;
module.exports.MethodNotAllowedError = MethodNotAllowedError;

View File

@ -0,0 +1,14 @@
// # Not found error
// Custom error class with status code and type prefilled.
function MethodNotAllowedError(message) {
this.message = message;
this.stack = new Error().stack;
this.code = 405;
this.type = this.name;
}
MethodNotAllowedError.prototype = Object.create(Error.prototype);
MethodNotAllowedError.prototype.name = 'MethodNotAllowedError';
module.exports = MethodNotAllowedError;

View File

@ -217,7 +217,8 @@ function serveSharedFile(file, type, maxAge) {
setupMiddleware = function setupMiddleware(blogAppInstance, adminApp) {
var logging = config.logging,
corePath = config.paths.corePath,
oauthServer = oauth2orize.createServer();
oauthServer = oauth2orize.createServer(),
apiRouter;
// silence JSHint without disabling unused check for the whole file
authStrategies = authStrategies;
@ -310,7 +311,19 @@ setupMiddleware = function setupMiddleware(blogAppInstance, adminApp) {
// ### Routing
// Set up API routes
blogApp.use(routes.apiBaseUri, routes.api(middleware));
apiRouter = routes.api(middleware);
blogApp.use(routes.apiBaseUri, apiRouter);
// ### Invalid method call on valid route
apiRouter.use(function (req, res, next) {
apiRouter.stack.forEach(function (item) {
if (item.regexp.test(req.path) && item.route !== undefined) {
return next(new errors.MethodNotAllowedError('Method not allowed'));
}
});
// Didn't match any path -> 404
res.status(404).json({errors: {type: 'NotFoundError', message: 'Unknown API endpoint.'}});
});
// Mount admin express app to /ghost and set up routes
adminApp.use(middleware.redirectToSetup);

View File

@ -0,0 +1,60 @@
/*global describe, it, before, after */
/*jshint expr:true*/
var supertest = require('supertest'),
testUtils = require('../../../utils'),
ghost = require('../../../../../core'),
request;
describe('API', function () {
var accesstoken = '';
before(function (done) {
// starting ghost automatically populates the db
// TODO: prevent db init, and manage bringing up the DB with fixtures ourselves
ghost().then(function (ghostServer) {
request = supertest.agent(ghostServer.rootApp);
}).then(function () {
return testUtils.doAuth(request);
}).then(function (token) {
accesstoken = token;
done();
}).catch(function (e) {
console.log('Ghost Error: ', e);
console.log(e.stack);
});
});
after(function (done) {
testUtils.clearData().then(function () {
done();
}).catch(done);
});
it('should return 404 when using invalid path', function (done) {
request.get(testUtils.API.getApiQuery('invalidpath/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect(404)
.end(function (err, res) {
/*jshint unused:false*/
if (err) {
return done(err);
}
done();
});
});
it('should return 405 Method not allowed when invalid method is used', function (done) {
request.put(testUtils.API.getApiQuery('db/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect(405)
.end(function (err, res) {
/*jshint unused:false*/
if (err) {
return done(err);
}
done();
});
});
});