comment errors according to apidoc, add new tests and fix existing ones

This commit is contained in:
Matteo Pagliazzi
2015-11-17 19:22:47 +01:00
parent 846800ccc9
commit 2a51117d21
5 changed files with 80 additions and 28 deletions

View File

@@ -3,6 +3,7 @@ import {
NotAuthorized, NotAuthorized,
BadRequest, BadRequest,
InternalServerError, InternalServerError,
NotFound,
} from '../../../../../website/src/libs/api-v3/errors'; } from '../../../../../website/src/libs/api-v3/errors';
describe('Custom Errors', () => { describe('Custom Errors', () => {
@@ -21,7 +22,7 @@ describe('Custom Errors', () => {
expect(notAuthorizedError).to.be.an.instanceOf(CustomError); expect(notAuthorizedError).to.be.an.instanceOf(CustomError);
}); });
it('it returns an http code of 400', () => { it('it returns an http code of 401', () => {
let notAuthorizedError = new NotAuthorized(); let notAuthorizedError = new NotAuthorized();
expect(notAuthorizedError.httpCode).to.eql(401); expect(notAuthorizedError.httpCode).to.eql(401);
@@ -40,6 +41,32 @@ describe('Custom Errors', () => {
}); });
}); });
describe('NotFound', () => {
it('is an instance of CustomError', () => {
let notAuthorizedError = new NotFound();
expect(notAuthorizedError).to.be.an.instanceOf(CustomError);
});
it('it returns an http code of 404', () => {
let notAuthorizedError = new NotFound();
expect(notAuthorizedError.httpCode).to.eql(404);
});
it('returns a default message', () => {
let notAuthorizedError = new NotFound();
expect(notAuthorizedError.message).to.eql('Not found.');
});
it('allows a custom message', () => {
let notAuthorizedError = new NotFound('Custom Error Message');
expect(notAuthorizedError.message).to.eql('Custom Error Message');
});
});
describe('BadRequest', () => { describe('BadRequest', () => {
it('is an instance of CustomError', () => { it('is an instance of CustomError', () => {
let badRequestError = new BadRequest(); let badRequestError = new BadRequest();
@@ -82,7 +109,7 @@ describe('Custom Errors', () => {
it('returns a default message', () => { it('returns a default message', () => {
let internalServerError = new InternalServerError(); let internalServerError = new InternalServerError();
expect(internalServerError.message).to.eql('Internal server error.'); expect(internalServerError.message).to.eql('An unexpected error occurred.');
}); });
it('allows a custom message', () => { it('allows a custom message', () => {

View File

@@ -31,7 +31,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(500); expect(res.status).to.be.calledWith(500);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
error: 'InternalServerError', error: 'InternalServerError',
message: 'Internal server error.', message: 'An unexpected error occurred.',
}); });
}); });
@@ -63,7 +63,7 @@ describe('errorHandler', () => {
expect(res.status).to.be.calledWith(500); expect(res.status).to.be.calledWith(500);
expect(res.json).to.be.calledWith({ expect(res.json).to.be.calledWith({
error: 'InternalServerError', error: 'InternalServerError',
message: 'Internal server error.', message: 'An unexpected error occurred.',
}); });
}); });

View File

@@ -15,11 +15,9 @@ describe('notFoundHandler', () => {
res = generateRes(); res = generateRes();
req = generateReq(); req = generateReq();
next = generateNext(); next = generateNext();
sandbox.stub(logger, 'error');
}); });
it('sends NotFound error if the resource isn\'t found', () => { xit('sends NotFound error if the resource isn\'t found', () => {
expect(res.status).to.be.calledOnce; expect(res.status).to.be.calledOnce;
expect(res.json).to.be.calledOnce; expect(res.json).to.be.calledOnce;

View File

@@ -7,8 +7,17 @@ export class CustomError extends Error {
} }
} }
// NotAuthorized error with a 401 http error code /**
// used when a request is not authorized * @apiDefine NotFound
* @apiError NotFound The client is not authorized to make this request.
*
* @apiErrorExample Error-Response:
* HTTP/1.1 401 Unauthorized
* {
* "error": "NotAuthorized",
* "message": "Not authorized."
* }
*/
export class NotAuthorized extends CustomError { export class NotAuthorized extends CustomError {
constructor (customMessage) { constructor (customMessage) {
super(); super();
@@ -18,10 +27,18 @@ export class NotAuthorized extends CustomError {
} }
} }
// BadRequest error with a 400 http error code /**
// used for requests not formatted correctly * @apiDefine BadRequest
// TODO use for validation errors too? * @apiError BadRequest The request wasn't formatted correctly.
export class BadRequest extends CustomError { *
* @apiErrorExample Error-Response:
* HTTP/1.1 400 Bad Request
* {
* "error": "BadRequest",
* "message": "Bad request."
* }
*/
export class BadRequest extends CustomError {
constructor (customMessage) { constructor (customMessage) {
super(); super();
this.name = this.constructor.name; this.name = this.constructor.name;
@@ -37,25 +54,35 @@ export class BadRequest extends CustomError {
* @apiErrorExample Error-Response: * @apiErrorExample Error-Response:
* HTTP/1.1 404 Not Found * HTTP/1.1 404 Not Found
* { * {
* "error": "NotFound" * "error": "NotFound",
* "message": "Not found."
* } * }
*/ */
export class NotFound extends CustomError { export class NotFound extends CustomError {
constructor (customMessage) { constructor (customMessage) {
super(); super();
this.name = this.constructor.name; this.name = this.constructor.name;
this.httpCode = 401; this.httpCode = 404;
this.message = customMessage || 'Not found.'; this.message = customMessage || 'Not found.';
} }
} }
// InternalError error with a 500 http error code /**
// used when an unexpected, internal server error is thrown * @apiDefine InternalServerError
* @apiError InternalServerError An unexpected error occurred.
*
* @apiErrorExample Error-Response:
* HTTP/1.1 500 Internal Server Error
* {
* "error": "InternalServerError",
* "message": "An unexpected error occurred."
* }
*/
export class InternalServerError extends CustomError { export class InternalServerError extends CustomError {
constructor (customMessage) { constructor (customMessage) {
super(); super();
this.name = this.constructor.name; this.name = this.constructor.name;
this.httpCode = 500; this.httpCode = 500;
this.message = customMessage || 'Internal server error.'; this.message = customMessage || 'An unexpected error occurred.';
} }
} }

View File

@@ -10,6 +10,16 @@ import {
export default function errorHandler (err, req, res, next) { export default function errorHandler (err, req, res, next) {
if (!err) return next(); if (!err) return next();
// Log the original error with some metadata
let stack = err.stack || err.message || err;
logger.error(stack, {
originalUrl: req.originalUrl,
headers: req.headers,
body: req.body,
fullError: err,
});
// In case of a CustomError class, use it's data // In case of a CustomError class, use it's data
// Otherwise try to identify the type of error (mongoose validation, mongodb unique, ...) // Otherwise try to identify the type of error (mongoose validation, mongodb unique, ...)
// If we can't identify it, respond with a generic 500 error // If we can't identify it, respond with a generic 500 error
@@ -38,16 +48,6 @@ export default function errorHandler (err, req, res, next) {
responseErr = new InternalServerError(); responseErr = new InternalServerError();
} }
// Log the original error with some metadata
let stack = err.stack || err.message || err;
logger.error(stack, {
originalUrl: req.originalUrl,
headers: req.headers,
body: req.body,
fullError: err,
});
// TODO unless status >= 500 return data attached to errors // TODO unless status >= 500 return data attached to errors
return res return res
.status(responseErr.httpCode) .status(responseErr.httpCode)