Skip to content

Commit 9bb24f6

Browse files
committed
feat: Updated to fastify 3.x.x.
1 parent f172ead commit 9bb24f6

20 files changed

+345
-352
lines changed

lib/handlers.js

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,46 @@
11
"use strict";
2+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3+
if (k2 === undefined) k2 = k;
4+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5+
}) : (function(o, m, k, k2) {
6+
if (k2 === undefined) k2 = k;
7+
o[k2] = m[k];
8+
}));
9+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10+
Object.defineProperty(o, "default", { enumerable: true, value: v });
11+
}) : function(o, v) {
12+
o["default"] = v;
13+
});
214
var __importStar = (this && this.__importStar) || function (mod) {
315
if (mod && mod.__esModule) return mod;
416
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;
17+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18+
__setModuleDefault(result, mod);
719
return result;
820
};
921
var __importDefault = (this && this.__importDefault) || function (mod) {
1022
return (mod && mod.__esModule) ? mod : { "default": mod };
1123
};
1224
Object.defineProperty(exports, "__esModule", { value: true });
25+
exports.handleErrors = exports.handleValidationError = exports.handleNotFoundError = void 0;
1326
const http_errors_1 = __importStar(require("http-errors"));
14-
const http_status_codes_1 = require("http-status-codes");
27+
const http_status_codes_1 = __importDefault(require("http-status-codes"));
1528
const statuses_1 = __importDefault(require("statuses"));
1629
const properties_1 = require("./properties");
1730
const utils_1 = require("./utils");
1831
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;
2532
function handleNotFoundError(request, reply) {
2633
handleErrors(new http_errors_1.NotFound('Not found.'), request, reply);
2734
}
2835
exports.handleNotFoundError = handleNotFoundError;
2936
function handleValidationError(error, request) {
3037
/*
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-
38+
As seen in https://github.com/fastify/fastify/blob/master/lib/validation.js
3639
the error.message will always start with the relative section (params, querystring, headers, body)
3740
and fastify throws on first failing section.
3841
*/
3942
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.', {
43+
return http_errors_1.default(http_status_codes_1.default.BAD_REQUEST, 'One or more validations failed trying to process your request.', {
4144
failedValidations: validation_1.convertValidationErrors(section, Reflect.get(request, section), error.validation)
4245
});
4346
}
@@ -63,29 +66,30 @@ function handleErrors(error, request, reply) {
6366
}
6467
}
6568
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()));
69+
error = http_errors_1.default(http_status_codes_1.default.UNSUPPORTED_MEDIA_TYPE, utils_1.upperFirst(validation_1.validationMessagesFormatters.contentType()));
6770
}
6871
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()));
72+
error = http_errors_1.default(http_status_codes_1.default.BAD_REQUEST, utils_1.upperFirst(validation_1.validationMessagesFormatters.jsonEmpty()));
7073
}
7174
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()));
75+
error = http_errors_1.default(http_status_codes_1.default.BAD_REQUEST, utils_1.upperFirst(validation_1.validationMessagesFormatters.json()));
7376
}
7477
// Get the status code
7578
let { statusCode, headers } = error;
7679
// Code outside HTTP range
7780
if (statusCode < 100 || statusCode > 599) {
78-
statusCode = http_status_codes_1.INTERNAL_SERVER_ERROR;
81+
statusCode = http_status_codes_1.default.INTERNAL_SERVER_ERROR;
7982
}
8083
// Create the body
8184
const body = {
8285
statusCode,
8386
code: error.code,
84-
error: statuses_1.default[statusCode.toString()],
87+
error: statuses_1.default(statusCode.toString()),
8588
message: error.message
8689
};
8790
properties_1.addAdditionalProperties(body, error);
8891
// Send the error back
92+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
8993
reply
9094
.code(statusCode)
9195
.headers(headers !== null && headers !== void 0 ? headers : {})

lib/index.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
11
"use strict";
2-
function __export(m) {
3-
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
4-
}
2+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3+
if (k2 === undefined) k2 = k;
4+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5+
}) : (function(o, m, k, k2) {
6+
if (k2 === undefined) k2 = k;
7+
o[k2] = m[k];
8+
}));
9+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
10+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11+
};
512
var __importDefault = (this && this.__importDefault) || function (mod) {
613
return (mod && mod.__esModule) ? mod : { "default": mod };
714
};
815
Object.defineProperty(exports, "__esModule", { value: true });
16+
exports.plugin = exports.validationMessagesFormatters = exports.niceJoin = exports.convertValidationErrors = exports.serializeError = exports.addAdditionalProperties = void 0;
917
const ajv_1 = __importDefault(require("ajv"));
1018
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
1119
const handlers_1 = require("./handlers");
1220
const validation_1 = require("./validation");
13-
__export(require("./handlers"));
21+
__exportStar(require("./handlers"), exports);
22+
__exportStar(require("./interfaces"), exports);
1423
var properties_1 = require("./properties");
15-
exports.addAdditionalProperties = properties_1.addAdditionalProperties;
16-
exports.serializeError = properties_1.serializeError;
24+
Object.defineProperty(exports, "addAdditionalProperties", { enumerable: true, get: function () { return properties_1.addAdditionalProperties; } });
25+
Object.defineProperty(exports, "serializeError", { enumerable: true, get: function () { return properties_1.serializeError; } });
1726
var validation_2 = require("./validation");
18-
exports.convertValidationErrors = validation_2.convertValidationErrors;
19-
exports.niceJoin = validation_2.niceJoin;
20-
exports.validationMessagesFormatters = validation_2.validationMessagesFormatters;
27+
Object.defineProperty(exports, "convertValidationErrors", { enumerable: true, get: function () { return validation_2.convertValidationErrors; } });
28+
Object.defineProperty(exports, "niceJoin", { enumerable: true, get: function () { return validation_2.niceJoin; } });
29+
Object.defineProperty(exports, "validationMessagesFormatters", { enumerable: true, get: function () { return validation_2.validationMessagesFormatters; } });
2130
exports.plugin = fastify_plugin_1.default(function (instance, options, done) {
2231
var _a, _b, _c;
2332
const isProduction = process.env.NODE_ENV === 'production';

lib/properties.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
3+
exports.serializeError = exports.addAdditionalProperties = void 0;
34
const processRoot = process.cwd();
45
function addAdditionalProperties(target, source) {
56
for (const v in source) {
@@ -17,12 +18,10 @@ function serializeError(error) {
1718
stack: ((_b = error.stack) !== null && _b !== void 0 ? _b : '')
1819
.split('\n')
1920
.slice(1)
20-
.map((s) => s
21-
.trim()
22-
.replace(/^at /, '')
23-
.replace(processRoot, '$ROOT'))
21+
.map((s) => s.trim().replace(/^at /, '').replace(processRoot, '$ROOT'))
2422
};
2523
addAdditionalProperties(serialized, error);
24+
serialized.code = undefined;
2625
return serialized;
2726
}
2827
exports.serializeError = serializeError;

lib/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
3+
exports.get = exports.upperFirst = void 0;
34
function upperFirst(source) {
4-
// tslint:disable-next-line strict-type-predicates
55
if (typeof source !== 'string' || !source.length) {
66
return source;
77
}

lib/validation.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
33
return (mod && mod.__esModule) ? mod : { "default": mod };
44
};
55
Object.defineProperty(exports, "__esModule", { value: true });
6+
exports.addResponseValidation = exports.convertValidationErrors = exports.validationMessagesFormatters = exports.niceJoin = void 0;
67
const http_errors_1 = __importDefault(require("http-errors"));
7-
const http_status_codes_1 = require("http-status-codes");
8+
const http_status_codes_1 = __importDefault(require("http-status-codes"));
89
const utils_1 = require("./utils");
910
function niceJoin(array, lastSeparator = ' and ', separator = ', ') {
1011
switch (array.length) {
@@ -168,26 +169,26 @@ function addResponseValidation(route) {
168169
if (!((_a = route.schema) === null || _a === void 0 ? void 0 : _a.response)) {
169170
return;
170171
}
171-
const validators = Object.entries(route.schema.response).reduce((accu, [code, schema]) => {
172-
accu[code] = this.responseValidatorSchemaCompiler.compile(schema);
173-
return accu;
174-
}, {});
172+
const validators = {};
173+
for (const [code, schema] of Object.entries(route.schema.response)) {
174+
validators[code] = this.responseValidatorSchemaCompiler.compile(schema);
175+
}
175176
// Note that this hook is not called for non JSON payloads therefore validation is not possible in such cases
176177
route.preSerialization = async function (_request, reply, payload) {
177-
const statusCode = reply.res.statusCode;
178+
const statusCode = reply.raw.statusCode;
178179
// Never validate error 500
179-
if (statusCode === http_status_codes_1.INTERNAL_SERVER_ERROR) {
180+
if (statusCode === http_status_codes_1.default.INTERNAL_SERVER_ERROR) {
180181
return payload;
181182
}
182183
// No validator, it means the HTTP status is not allowed
183184
const validator = validators[statusCode];
184185
if (!validator) {
185-
throw http_errors_1.default(http_status_codes_1.INTERNAL_SERVER_ERROR, exports.validationMessagesFormatters.invalidResponseCode(statusCode));
186+
throw http_errors_1.default(http_status_codes_1.default.INTERNAL_SERVER_ERROR, exports.validationMessagesFormatters.invalidResponseCode(statusCode));
186187
}
187188
// Now validate the payload
188189
const valid = validator(payload);
189190
if (!valid) {
190-
throw http_errors_1.default(http_status_codes_1.INTERNAL_SERVER_ERROR, exports.validationMessagesFormatters.invalidResponse(statusCode), {
191+
throw http_errors_1.default(http_status_codes_1.default.INTERNAL_SERVER_ERROR, exports.validationMessagesFormatters.invalidResponse(statusCode), {
191192
failedValidations: convertValidationErrors('response', payload, validator.errors)
192193
});
193194
}

package.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,22 @@
3535
"postpublish": "git push origin && git push origin -f --tags"
3636
},
3737
"dependencies": {
38-
"ajv": "^6.12.0",
39-
"fastify-plugin": "^1.6.1",
40-
"http-errors": "^1.7.3",
41-
"http-status-codes": "^1.4.0",
42-
"statuses": "^1.5.0"
38+
"ajv": "^6.12.5",
39+
"fastify-plugin": "^2.3.4",
40+
"http-errors": "^1.8.0",
41+
"http-status-codes": "^2.1.4",
42+
"statuses": "^2.0.0"
4343
},
4444
"devDependencies": {
45-
"@cowtech/eslint-config": "^6.8.4",
46-
"@types/http-errors": "^1.6.3",
47-
"@types/node": "^13.9.0",
48-
"@types/statuses": "^1.5.0",
49-
"fastify": "^2.12.1",
50-
"prettier": "^1.19.1",
51-
"tap": "^14.10.6",
52-
"typescript": "^3.8.3"
45+
"@cowtech/eslint-config": "^6.9.2",
46+
"@types/http-errors": "^1.8.0",
47+
"@types/node": "^14.11.2",
48+
"@types/statuses": "^2.0.0",
49+
"@types/tap": "^14.10.1",
50+
"fastify": "^3.4.1",
51+
"prettier": "^2.1.2",
52+
"tap": "^14.10.8",
53+
"typescript": "^4.0.3"
5354
},
5455
"engines": {
5556
"node": ">=12.15.0"

prettier.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ module.exports = {
22
printWidth: 120,
33
semi: false,
44
singleQuote: true,
5-
bracketSpacing: true
5+
bracketSpacing: true,
6+
trailingComma: 'none',
7+
arrowParens: 'avoid'
68
}

src/handlers.ts

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,37 @@
11
import { FastifyError, FastifyReply, FastifyRequest } from 'fastify'
22
import createError, { HttpError, InternalServerError, NotFound } from 'http-errors'
3-
import { BAD_REQUEST, INTERNAL_SERVER_ERROR, UNSUPPORTED_MEDIA_TYPE } from 'http-status-codes'
3+
import StatusCodes from 'http-status-codes'
44
import statuses from 'statuses'
5-
import { FastifyDecoratedRequest, GenericObject, NodeError, RequestSection } from './interfaces'
5+
import { GenericObject, NodeError, RequestSection } from './interfaces'
66
import { addAdditionalProperties, serializeError } from './properties'
77
import { upperFirst } from './utils'
88
import { convertValidationErrors, validationMessagesFormatters } from './validation'
99

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 {
10+
export function handleNotFoundError(request: FastifyRequest, reply: FastifyReply): void {
1511
handleErrors(new NotFound('Not found.'), request, reply)
1612
}
1713

18-
export function handleValidationError(error: FastifyError, request: FastifyRequest): FastifyError {
14+
export function handleValidationError(error: FastifyError, request: FastifyRequest): HttpError {
1915
/*
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-
16+
As seen in https://github.com/fastify/fastify/blob/master/lib/validation.js
2517
the error.message will always start with the relative section (params, querystring, headers, body)
2618
and fastify throws on first failing section.
2719
*/
2820
const section = error.message.match(/^\w+/)![0] as RequestSection
2921

30-
return createError(BAD_REQUEST, 'One or more validations failed trying to process your request.', {
22+
return createError(StatusCodes.BAD_REQUEST, 'One or more validations failed trying to process your request.', {
3123
failedValidations: convertValidationErrors(section, Reflect.get(request, section), error.validation!)
3224
})
3325
}
3426

35-
export function handleErrors(
36-
error: FastifyError,
37-
request: FastifyDecoratedRequest,
38-
reply: FastifyReply<unknown>
39-
): void {
27+
export function handleErrors(error: FastifyError | HttpError, request: FastifyRequest, reply: FastifyReply): void {
4028
// It is a generic error, handle it
4129
const code = (error as NodeError).code
4230

43-
if (!('statusCode' in (error as HttpError))) {
31+
if (!('statusCode' in error)) {
4432
if ('validation' in error && request.errorProperties?.convertValidationErrors) {
4533
// If it is a validation error, convert errors to human friendly format
46-
error = handleValidationError(error, request)
34+
error = handleValidationError(error as FastifyError, request)
4735
} else if (request.errorProperties?.hideUnhandledErrors) {
4836
// It is requested to hide the error, just log it and then create a generic one
4937
request.log.error({ error: serializeError(error) })
@@ -54,32 +42,33 @@ export function handleErrors(
5442
Object.defineProperty(error, 'stack', { enumerable: true })
5543
}
5644
} else if (code === 'INVALID_CONTENT_TYPE' || code === 'FST_ERR_CTP_INVALID_MEDIA_TYPE') {
57-
error = createError(UNSUPPORTED_MEDIA_TYPE, upperFirst(validationMessagesFormatters.contentType()))
45+
error = createError(StatusCodes.UNSUPPORTED_MEDIA_TYPE, upperFirst(validationMessagesFormatters.contentType()))
5846
} else if (code === 'FST_ERR_CTP_EMPTY_JSON_BODY') {
59-
error = createError(BAD_REQUEST, upperFirst(validationMessagesFormatters.jsonEmpty()))
47+
error = createError(StatusCodes.BAD_REQUEST, upperFirst(validationMessagesFormatters.jsonEmpty()))
6048
} else if (code === 'MALFORMED_JSON' || error.message === 'Invalid JSON' || error.stack!.includes('at JSON.parse')) {
61-
error = createError(BAD_REQUEST, upperFirst(validationMessagesFormatters.json()))
49+
error = createError(StatusCodes.BAD_REQUEST, upperFirst(validationMessagesFormatters.json()))
6250
}
6351

6452
// Get the status code
6553
let { statusCode, headers } = error as HttpError
6654

6755
// Code outside HTTP range
6856
if (statusCode < 100 || statusCode > 599) {
69-
statusCode = INTERNAL_SERVER_ERROR
57+
statusCode = StatusCodes.INTERNAL_SERVER_ERROR
7058
}
7159

7260
// Create the body
7361
const body: GenericObject = {
7462
statusCode,
7563
code: (error as NodeError).code,
76-
error: statuses[statusCode.toString()],
64+
error: statuses(statusCode.toString()),
7765
message: error.message
7866
}
7967

8068
addAdditionalProperties(body, error)
8169

8270
// Send the error back
71+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
8372
reply
8473
.code(statusCode)
8574
.headers(headers ?? {})

0 commit comments

Comments
 (0)