backend-error 1.0.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -1
- package/dist/core/httpErrorFormatter.d.ts +2 -4
- package/dist/core/httpErrorFormatter.js +32 -70
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
BackendError is a lightweight utility for structured and user-aware error handling in Node.js backends. It helps distinguish operational errors from unexpected crashes, and supports standardized error responses across services.
|
|
4
4
|
|
|
5
|
+
> ⚠️ Note: backend-error is not a middleware — it's a flexible utility for throwing and formatting structured errors. It works seamlessly with Express, Cloud Functions, and any other Node.js-based backend environment where you want standardized, user-aware error responses.
|
|
6
|
+
|
|
7
|
+
> 💬 Tip: This package doesn't handle headers or CORS. If you're building an API for browsers, remember to configure CORS separately.
|
|
8
|
+
|
|
5
9
|
[](https://github.com/eriksturesson/backendError)
|
|
6
10
|
[](https://www.npmjs.com/package/backend-error)
|
|
7
11
|
|
|
@@ -106,7 +110,32 @@ export interface BackendErrorOptions {
|
|
|
106
110
|
}
|
|
107
111
|
```
|
|
108
112
|
|
|
109
|
-
|
|
113
|
+
## 🎨 Works well with [error-drawings](https://www.npmjs.com/package/error-drawings)
|
|
114
|
+
|
|
115
|
+

|
|
116
|
+

|
|
117
|
+
|
|
118
|
+
`npm install error-drawings`
|
|
119
|
+
|
|
120
|
+
If you want fun and visual error output during development, you can combine backend-error with error-drawings. Both libraries support the same severity field ("info" | "warning" | "error" | "critical"), making them plug-and-play together.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { BackendError } from "backend-error";
|
|
124
|
+
import drawLog from "error-drawings";
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
throw BackendError.Forbidden("No access to resource");
|
|
128
|
+
} catch (err) {
|
|
129
|
+
const isCritical = !(err instanceof BackendError && err.isOperational) || err.code >= 500;
|
|
130
|
+
if (isCritical) {
|
|
131
|
+
// 🔥 Draw dramatic error output to highlight critical issues during development
|
|
132
|
+
// 🧠 Important: log BEFORE formatting, since the formatter may hide details if showUser is false
|
|
133
|
+
drawLog(err);
|
|
134
|
+
}
|
|
135
|
+
const { status, body } = await httpErrorFormatter(err); //Use the formatter as always
|
|
136
|
+
res.status(status).json(body);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
110
139
|
|
|
111
140
|
---
|
|
112
141
|
|
|
@@ -10,81 +10,43 @@ var __assign = (this && this.__assign) || function () {
|
|
|
10
10
|
};
|
|
11
11
|
return __assign.apply(this, arguments);
|
|
12
12
|
};
|
|
13
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
-
function step(op) {
|
|
27
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
-
switch (op[0]) {
|
|
32
|
-
case 0: case 1: t = op; break;
|
|
33
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
-
default:
|
|
37
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
-
if (t[2]) _.ops.pop();
|
|
42
|
-
_.trys.pop(); continue;
|
|
43
|
-
}
|
|
44
|
-
op = body.call(thisArg, _);
|
|
45
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
14
|
exports.httpErrorFormatter = void 0;
|
|
51
15
|
var BackendError_1 = require("./BackendError");
|
|
52
16
|
function isValidStatusCode(code) {
|
|
53
17
|
return typeof code === "number" && Number.isInteger(code) && code >= 100 && code <= 599;
|
|
54
18
|
}
|
|
55
|
-
function httpErrorFormatter(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
var status_1
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
});
|
|
88
|
-
});
|
|
19
|
+
function httpErrorFormatter(err) {
|
|
20
|
+
// Handle your custom BackendError type
|
|
21
|
+
if (err instanceof BackendError_1.BackendError) {
|
|
22
|
+
var status_1 = isValidStatusCode(err.code) ? err.code : 400;
|
|
23
|
+
// If developer explicitly set showUser, trust that; otherwise default: true for 4xx, false for 5xx
|
|
24
|
+
var showUser_1 = typeof err.showUser === "boolean" ? err.showUser : status_1 < 500;
|
|
25
|
+
var message_1 = err.message || "Error";
|
|
26
|
+
// If showUser is true, return detailed info including data, code, severity; else generic message
|
|
27
|
+
var body_1 = showUser_1
|
|
28
|
+
? __assign(__assign({ message: message_1 }, (err.data !== undefined && { data: err.data })), { code: status_1, severity: err.severity }) : { message: "Internal Server Error" };
|
|
29
|
+
return { status: status_1, body: body_1, showUser: showUser_1, message: message_1 };
|
|
30
|
+
}
|
|
31
|
+
// Handle generic Error or string or unknown
|
|
32
|
+
var status = 500;
|
|
33
|
+
var message = "Internal Server Error";
|
|
34
|
+
var showUser = false;
|
|
35
|
+
if (err instanceof Error) {
|
|
36
|
+
message = err.message;
|
|
37
|
+
// Try to extract HTTP status code from common fields 'status' or 'code'
|
|
38
|
+
var maybeStatus = err.status || err.code;
|
|
39
|
+
if (isValidStatusCode(maybeStatus)) {
|
|
40
|
+
status = maybeStatus;
|
|
41
|
+
showUser = status < 500; // show message for 4xx errors by default
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else if (typeof err === "string") {
|
|
45
|
+
message = err;
|
|
46
|
+
status = 400;
|
|
47
|
+
showUser = true;
|
|
48
|
+
}
|
|
49
|
+
var body = showUser ? { message: message } : { message: "Internal Server Error" };
|
|
50
|
+
return { status: status, body: body, showUser: showUser, message: message };
|
|
89
51
|
}
|
|
90
52
|
exports.httpErrorFormatter = httpErrorFormatter;
|