Skip to content

Commit 5b297ed

Browse files
author
Shogun
committed
fix: Allow CommonJS default import. Fixes #1.
1 parent 8e7c2bc commit 5b297ed

File tree

9 files changed

+220
-184
lines changed

9 files changed

+220
-184
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const createError = require('http-errors')
4949
server.register(require('fastify-errors-properties'))
5050

5151
server.get('/invalid', {
52-
handler: function(request, reply) {
52+
handler: async function(request, reply) {
5353
throw createError(404, 'You are not supposed to reach this.', { header: { 'X-Req-Id': request.id, id: 123 } })
5454
}
5555
})

lib/handlers.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"use strict";
2+
var __importStar = (this && this.__importStar) || function (mod) {
3+
if (mod && mod.__esModule) return mod;
4+
var result = {};
5+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
6+
result["default"] = mod;
7+
return result;
8+
};
9+
var __importDefault = (this && this.__importDefault) || function (mod) {
10+
return (mod && mod.__esModule) ? mod : { "default": mod };
11+
};
12+
Object.defineProperty(exports, "__esModule", { value: true });
13+
const http_errors_1 = __importStar(require("http-errors"));
14+
const http_status_codes_1 = require("http-status-codes");
15+
const statuses_1 = __importDefault(require("statuses"));
16+
const properties_1 = require("./properties");
17+
const utils_1 = require("./utils");
18+
const validation_1 = require("./validation");
19+
var properties_2 = require("./properties");
20+
exports.addAdditionalProperties = properties_2.addAdditionalProperties;
21+
var validation_2 = require("./validation");
22+
exports.convertValidationErrors = validation_2.convertValidationErrors;
23+
exports.niceJoin = validation_2.niceJoin;
24+
exports.validationMessagesFormatters = validation_2.validationMessagesFormatters;
25+
function handleNotFoundError(request, reply) {
26+
handleErrors(new http_errors_1.NotFound('Not found.'), request, reply);
27+
}
28+
exports.handleNotFoundError = handleNotFoundError;
29+
function handleValidationError(error, request) {
30+
/*
31+
As seen in
32+
https://github.com/fastify/fastify/blob/master/lib/validation.js#L96
33+
and
34+
https://github.com/fastify/fastify/blob/master/lib/validation.js#L156,
35+
36+
the error.message will always start with the relative section (params, querystring, headers, body)
37+
and fastify throws on first failing section.
38+
*/
39+
const section = error.message.match(/^\w+/)[0];
40+
return http_errors_1.default(http_status_codes_1.BAD_REQUEST, 'One or more validations failed trying to process your request.', {
41+
failedValidations: validation_1.convertValidationErrors(section, Reflect.get(request, section), error.validation)
42+
});
43+
}
44+
exports.handleValidationError = handleValidationError;
45+
function handleErrors(error, request, reply) {
46+
var _a, _b;
47+
// It is a generic error, handle it
48+
const code = error.code;
49+
if (!('statusCode' in error)) {
50+
if ('validation' in error && ((_a = request.errorProperties) === null || _a === void 0 ? void 0 : _a.convertValidationErrors)) {
51+
// If it is a validation error, convert errors to human friendly format
52+
error = handleValidationError(error, request);
53+
}
54+
else if ((_b = request.errorProperties) === null || _b === void 0 ? void 0 : _b.hideUnhandledErrors) {
55+
// It is requested to hide the error, just log it and then create a generic one
56+
request.log.error({ error: properties_1.serializeError(error) });
57+
error = new http_errors_1.InternalServerError('An error occurred trying to process your request.');
58+
}
59+
else {
60+
// Wrap in a http-error, making the stack explicitily available
61+
error = Object.assign(new http_errors_1.InternalServerError(error.message), properties_1.serializeError(error));
62+
Object.defineProperty(error, 'stack', { enumerable: true });
63+
}
64+
}
65+
else if (code === 'INVALID_CONTENT_TYPE' || code === 'FST_ERR_CTP_INVALID_MEDIA_TYPE') {
66+
error = http_errors_1.default(http_status_codes_1.UNSUPPORTED_MEDIA_TYPE, utils_1.upperFirst(validation_1.validationMessagesFormatters.contentType()));
67+
}
68+
else if (code === 'FST_ERR_CTP_EMPTY_JSON_BODY') {
69+
error = http_errors_1.default(http_status_codes_1.BAD_REQUEST, utils_1.upperFirst(validation_1.validationMessagesFormatters.jsonEmpty()));
70+
}
71+
else if (code === 'MALFORMED_JSON' || error.message === 'Invalid JSON' || error.stack.includes('at JSON.parse')) {
72+
error = http_errors_1.default(http_status_codes_1.BAD_REQUEST, utils_1.upperFirst(validation_1.validationMessagesFormatters.json()));
73+
}
74+
// Get the status code
75+
let { statusCode, headers } = error;
76+
// Code outside HTTP range
77+
if (statusCode < 100 || statusCode > 599) {
78+
statusCode = http_status_codes_1.INTERNAL_SERVER_ERROR;
79+
}
80+
// Create the body
81+
const body = {
82+
statusCode,
83+
code: error.code,
84+
error: statuses_1.default[statusCode.toString()],
85+
message: error.message
86+
};
87+
properties_1.addAdditionalProperties(body, error);
88+
// Send the error back
89+
reply
90+
.code(statusCode)
91+
.headers(headers || {})
92+
.type('application/json')
93+
.send(body);
94+
}
95+
exports.handleErrors = handleErrors;

lib/index.js

Lines changed: 13 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,31 @@
11
"use strict";
2+
function __export(m) {
3+
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
4+
}
25
var __importDefault = (this && this.__importDefault) || function (mod) {
36
return (mod && mod.__esModule) ? mod : { "default": mod };
47
};
5-
var __importStar = (this && this.__importStar) || function (mod) {
6-
if (mod && mod.__esModule) return mod;
7-
var result = {};
8-
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
9-
result["default"] = mod;
10-
return result;
11-
};
128
Object.defineProperty(exports, "__esModule", { value: true });
139
const ajv_1 = __importDefault(require("ajv"));
1410
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
15-
const http_errors_1 = __importStar(require("http-errors"));
16-
const http_status_codes_1 = require("http-status-codes");
17-
const statuses_1 = __importDefault(require("statuses"));
18-
const properties_1 = require("./properties");
19-
const utils_1 = require("./utils");
11+
const handlers_1 = require("./handlers");
2012
const validation_1 = require("./validation");
21-
var properties_2 = require("./properties");
22-
exports.addAdditionalProperties = properties_2.addAdditionalProperties;
13+
__export(require("./handlers"));
14+
var properties_1 = require("./properties");
15+
exports.addAdditionalProperties = properties_1.addAdditionalProperties;
2316
var validation_2 = require("./validation");
2417
exports.convertValidationErrors = validation_2.convertValidationErrors;
2518
exports.niceJoin = validation_2.niceJoin;
2619
exports.validationMessagesFormatters = validation_2.validationMessagesFormatters;
27-
function handleNotFoundError(request, reply) {
28-
handleErrors(new http_errors_1.NotFound('Not found.'), request, reply);
29-
}
30-
exports.handleNotFoundError = handleNotFoundError;
31-
function handleValidationError(error, request) {
32-
/*
33-
As seen in
34-
https://github.com/fastify/fastify/blob/master/lib/validation.js#L96
35-
and
36-
https://github.com/fastify/fastify/blob/master/lib/validation.js#L156,
37-
38-
the error.message will always start with the relative section (params, querystring, headers, body)
39-
and fastify throws on first failing section.
40-
*/
41-
const section = error.message.match(/^\w+/)[0];
42-
return http_errors_1.default(http_status_codes_1.BAD_REQUEST, 'One or more validations failed trying to process your request.', {
43-
failedValidations: validation_1.convertValidationErrors(section, Reflect.get(request, section), error.validation)
44-
});
45-
}
46-
exports.handleValidationError = handleValidationError;
47-
function handleErrors(error, request, reply) {
48-
var _a, _b;
49-
// It is a generic error, handle it
50-
const code = error.code;
51-
if (!('statusCode' in error)) {
52-
if ('validation' in error && ((_a = request.errorProperties) === null || _a === void 0 ? void 0 : _a.convertValidationErrors)) {
53-
// If it is a validation error, convert errors to human friendly format
54-
error = handleValidationError(error, request);
55-
}
56-
else if ((_b = request.errorProperties) === null || _b === void 0 ? void 0 : _b.hideUnhandledErrors) {
57-
// It is requested to hide the error, just log it and then create a generic one
58-
request.log.error({ error: properties_1.serializeError(error) });
59-
error = new http_errors_1.InternalServerError('An error occurred trying to process your request.');
60-
}
61-
else {
62-
// Wrap in a http-error, making the stack explicitily available
63-
error = Object.assign(new http_errors_1.InternalServerError(error.message), properties_1.serializeError(error));
64-
Object.defineProperty(error, 'stack', { enumerable: true });
65-
}
66-
}
67-
else if (code === 'INVALID_CONTENT_TYPE' || code === 'FST_ERR_CTP_INVALID_MEDIA_TYPE') {
68-
error = http_errors_1.default(http_status_codes_1.UNSUPPORTED_MEDIA_TYPE, utils_1.upperFirst(validation_1.validationMessagesFormatters.contentType()));
69-
}
70-
else if (code === 'FST_ERR_CTP_EMPTY_JSON_BODY') {
71-
error = http_errors_1.default(http_status_codes_1.BAD_REQUEST, utils_1.upperFirst(validation_1.validationMessagesFormatters.jsonEmpty()));
72-
}
73-
else if (code === 'MALFORMED_JSON' || error.message === 'Invalid JSON' || error.stack.includes('at JSON.parse')) {
74-
error = http_errors_1.default(http_status_codes_1.BAD_REQUEST, utils_1.upperFirst(validation_1.validationMessagesFormatters.json()));
75-
}
76-
// Get the status code
77-
let { statusCode, headers } = error;
78-
// Code outside HTTP range
79-
if (statusCode < 100 || statusCode > 599) {
80-
statusCode = http_status_codes_1.INTERNAL_SERVER_ERROR;
81-
}
82-
// Create the body
83-
const body = {
84-
statusCode,
85-
code: error.code,
86-
error: statuses_1.default[statusCode.toString()],
87-
message: error.message
88-
};
89-
properties_1.addAdditionalProperties(body, error);
90-
// Send the error back
91-
reply
92-
.code(statusCode)
93-
.headers(headers || {})
94-
.type('application/json')
95-
.send(body);
96-
}
97-
exports.handleErrors = handleErrors;
98-
exports.default = fastify_plugin_1.default(function (instance, options, done) {
20+
exports.plugin = fastify_plugin_1.default(function (instance, options, done) {
9921
var _a, _b, _c;
10022
const isProduction = process.env.NODE_ENV === 'production';
10123
const hideUnhandledErrors = (_a = options.hideUnhandledErrors, (_a !== null && _a !== void 0 ? _a : isProduction));
10224
const convertValidationErrors = (_b = options.convertValidationErrors, (_b !== null && _b !== void 0 ? _b : true));
10325
const convertResponsesValidationErrors = (_c = options.convertResponsesValidationErrors, (_c !== null && _c !== void 0 ? _c : !isProduction));
10426
instance.decorateRequest('errorProperties', { hideUnhandledErrors, convertValidationErrors });
105-
instance.setErrorHandler(handleErrors);
106-
instance.setNotFoundHandler(handleNotFoundError);
27+
instance.setErrorHandler(handlers_1.handleErrors);
28+
instance.setNotFoundHandler(handlers_1.handleNotFoundError);
10729
if (convertResponsesValidationErrors) {
10830
instance.decorate('responseValidatorSchemaCompiler', new ajv_1.default({
10931
// The fastify defaults, with the exception of removeAdditional and coerceTypes, which have been reversed
@@ -117,3 +39,6 @@ exports.default = fastify_plugin_1.default(function (instance, options, done) {
11739
}
11840
done();
11941
}, { name: 'fastify-errors-properties' });
42+
// prettier-ignore
43+
module.exports = exports.plugin;
44+
Object.assign(module.exports, exports);

src/handlers.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { FastifyError, FastifyReply, FastifyRequest } from 'fastify'
2+
import createError, { HttpError, InternalServerError, NotFound } from 'http-errors'
3+
import { BAD_REQUEST, INTERNAL_SERVER_ERROR, UNSUPPORTED_MEDIA_TYPE } from 'http-status-codes'
4+
import statuses from 'statuses'
5+
import { FastifyDecoratedRequest, GenericObject, NodeError, RequestSection } from './interfaces'
6+
import { addAdditionalProperties, serializeError } from './properties'
7+
import { upperFirst } from './utils'
8+
import { convertValidationErrors, validationMessagesFormatters } from './validation'
9+
10+
export * from './interfaces'
11+
export { addAdditionalProperties } from './properties'
12+
export { convertValidationErrors, niceJoin, validationMessagesFormatters } from './validation'
13+
14+
export function handleNotFoundError(request: FastifyRequest, reply: FastifyReply<unknown>): void {
15+
handleErrors(new NotFound('Not found.'), request, reply)
16+
}
17+
18+
export function handleValidationError(error: FastifyError, request: FastifyRequest): FastifyError {
19+
/*
20+
As seen in
21+
https://github.com/fastify/fastify/blob/master/lib/validation.js#L96
22+
and
23+
https://github.com/fastify/fastify/blob/master/lib/validation.js#L156,
24+
25+
the error.message will always start with the relative section (params, querystring, headers, body)
26+
and fastify throws on first failing section.
27+
*/
28+
const section = error.message.match(/^\w+/)![0] as RequestSection
29+
30+
return createError(BAD_REQUEST, 'One or more validations failed trying to process your request.', {
31+
failedValidations: convertValidationErrors(section, Reflect.get(request, section), error.validation!)
32+
})
33+
}
34+
35+
export function handleErrors(
36+
error: FastifyError,
37+
request: FastifyDecoratedRequest,
38+
reply: FastifyReply<unknown>
39+
): void {
40+
// It is a generic error, handle it
41+
const code = (error as NodeError).code
42+
43+
if (!('statusCode' in (error as HttpError))) {
44+
if ('validation' in error && request.errorProperties?.convertValidationErrors) {
45+
// If it is a validation error, convert errors to human friendly format
46+
error = handleValidationError(error, request)
47+
} else if (request.errorProperties?.hideUnhandledErrors) {
48+
// It is requested to hide the error, just log it and then create a generic one
49+
request.log.error({ error: serializeError(error) })
50+
error = new InternalServerError('An error occurred trying to process your request.')
51+
} else {
52+
// Wrap in a http-error, making the stack explicitily available
53+
error = Object.assign(new InternalServerError(error.message), serializeError(error))
54+
Object.defineProperty(error, 'stack', { enumerable: true })
55+
}
56+
} else if (code === 'INVALID_CONTENT_TYPE' || code === 'FST_ERR_CTP_INVALID_MEDIA_TYPE') {
57+
error = createError(UNSUPPORTED_MEDIA_TYPE, upperFirst(validationMessagesFormatters.contentType()))
58+
} else if (code === 'FST_ERR_CTP_EMPTY_JSON_BODY') {
59+
error = createError(BAD_REQUEST, upperFirst(validationMessagesFormatters.jsonEmpty()))
60+
} else if (code === 'MALFORMED_JSON' || error.message === 'Invalid JSON' || error.stack!.includes('at JSON.parse')) {
61+
error = createError(BAD_REQUEST, upperFirst(validationMessagesFormatters.json()))
62+
}
63+
64+
// Get the status code
65+
let { statusCode, headers } = error as HttpError
66+
67+
// Code outside HTTP range
68+
if (statusCode < 100 || statusCode > 599) {
69+
statusCode = INTERNAL_SERVER_ERROR
70+
}
71+
72+
// Create the body
73+
const body: GenericObject = {
74+
statusCode,
75+
code: (error as NodeError).code,
76+
error: statuses[statusCode.toString()],
77+
message: error.message
78+
}
79+
80+
addAdditionalProperties(body, error)
81+
82+
// Send the error back
83+
reply
84+
.code(statusCode)
85+
.headers(headers || {})
86+
.type('application/json')
87+
.send(body)
88+
}

0 commit comments

Comments
 (0)