backend-error 1.0.4 → 1.1.1

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 CHANGED
@@ -1,33 +1,58 @@
1
- # Backend-error
1
+ # backend-error
2
2
 
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.
3
+ ![npm](https://img.shields.io/npm/v/backend-error)
4
+ ![downloads](https://img.shields.io/npm/dm/backend-error)
5
+ ![license](https://img.shields.io/npm/l/backend-error)
4
6
 
5
- [![GitHub package.json version (master)](https://img.shields.io/github/package-json/v/eriksturesson/backendError/master)](https://github.com/eriksturesson/backendError)
6
- [![npm](https://img.shields.io/npm/dy/backend-error?label=npm%20downloads)](https://www.npmjs.com/package/backend-error)
7
+ `backend-error` is a lightweight Node.js / TypeScript utility that formats all errors—custom or native—into standardized HTTP responses with correct status codes and user-friendly messages. The `httpErrorFormatter` ensures secure, consistent error output by controlling what is exposed to the frontend.
7
8
 
8
- ## Installation
9
+ ---
10
+
11
+ ## 📦 Installation
9
12
 
10
13
  ```bash
11
14
  npm install backend-error
12
15
  ```
13
16
 
14
- ## 🔥 Custom BackendError class
15
-
16
- Use `BackendError` class for standardized backend error handling:
17
+ ---
17
18
 
18
- ## Usage
19
+ ## 🚀 Throw `BackendError`, catch with `httpErrorFormatter`
19
20
 
20
21
  ```ts
21
- import { BackendError } from "backend-error";
22
+ import { BackendError, httpErrorFormatter } from "backend-error";
22
23
 
23
- throw BackendError.BadRequest("Missing required field");
24
+ app.post("/signup", async (req, res) => {
25
+ try {
26
+ const auth = req.headers.authorization;
27
+ const { email, id } = req.body;
28
+ if (!auth) throw BackendError.Unauthorized("Missing auth token"); // 401, showUser:true
29
+ if (!email) throw BackendError.BadRequest("Email is required"); // 400, showUser:true
30
+ const user = await getUser(req.params.id);
31
+ if (!user) throw BackendError.NotFound("User not found"); // 404, showUser:true
32
+
33
+ // Normal logic...
34
+ } catch (err) {
35
+ const { status, body } = httpErrorFormatter(err); // Handles BackendError and native Error safely
36
+ res.status(status).json(body);
37
+ }
38
+ });
24
39
  ```
25
40
 
26
- Or construct it manually for full control:
41
+ No manual showUser checks handled automatically by the formatter
42
+ ✅ Returns generic 500 for critical or unknown errors (or if `showUser` is false)
43
+ ✅ Formatter supports both BackendError instances and native Error objects
44
+
45
+ > The httpErrorFormatter inspects any error, formats it consistently, and decides what message is safe to show to users.
46
+
47
+ ---
48
+
49
+ ## ✨ Custom BackendError creation
50
+
51
+ If you prefer, create your own error with full control including custom metadata:
27
52
 
28
53
  ```ts
29
54
  const error = new BackendError({
30
- message: "Something went terribly wrong",
55
+ message: "Something went wrong",
31
56
  severity: "critical",
32
57
  showUser: true,
33
58
  code: 500,
@@ -35,35 +60,37 @@ const error = new BackendError({
35
60
  });
36
61
  ```
37
62
 
38
- Properties available:
63
+ ### Selected BackendError options
39
64
 
40
- - `message`: The error message
65
+ - `message`: Error message
41
66
  - `code`: HTTP status code
42
- - `isOperational`: Marks it as a handled error (vs. crash)
43
- - `showUser`: Whether frontend should show the message
67
+ - `showUser`: Whether to expose the message to frontend clients
44
68
  - `severity`: "info" | "warning" | "error" | "critical"
45
- - `data`: Additional metadata (optional and anything accepted)
69
+ - `data`: Optional metadata
46
70
 
47
- ## 🧠 Example where you also import `httpErrorFormatter`:
71
+ ---
72
+
73
+ ## ⚙️ Static error helpers
48
74
 
49
75
  ```ts
50
- import { BackendError, httpErrorFormatter } from "backend-error";
51
- try {
52
- const user = null;
53
- if (!user) throw BackendError.NotFound("User not found");
54
- res.json(user);
55
- } catch (err) {
56
- const { status, body, message, showUser } = await httpErrorFormatter(err);
57
- res.status(status).json(body);
58
- }
76
+ BackendError.BadRequest("..."); // 400, showUser: true
77
+ BackendError.Unauthorized("..."); // 401, showUser: true
78
+ BackendError.Forbidden("..."); // 403, showUser: true
79
+ BackendError.NotFound("..."); // 404, showUser: true
80
+ BackendError.Conflict("..."); // 409, showUser: true
81
+ BackendError.UnprocessableEntity("..."); // 422, showUser: true
82
+ BackendError.Internal("..."); // 500, showUser: false
83
+ BackendError.ServiceUnavailable("..."); // 503, showUser: false
59
84
  ```
60
85
 
61
- ## 🧠 Example of manual showUser handling (done automatically in httpErrorFormatter above)
86
+ ---
87
+
88
+ ## 🧠 Manual error handling (if not using `httpErrorFormatter`)
62
89
 
63
90
  ```ts
64
91
  import { BackendError } from "backend-error";
65
92
 
66
- app.get("/user/:id", async (req, res, next) => {
93
+ app.get("/user/:id", async (req, res) => {
67
94
  try {
68
95
  const user = null;
69
96
  if (!user) throw BackendError.NotFound("User not found");
@@ -78,24 +105,13 @@ app.get("/user/:id", async (req, res, next) => {
78
105
  });
79
106
  ```
80
107
 
81
- ## Available static error constructors
82
-
83
- - `BackendError.BadRequest(message: string)` // 400, showUser: true
84
- - `BackendError.Unauthorized(message: string)` // 401, showUser: true
85
- - `BackendError.Forbidden(message: string)` // 403, showUser: true
86
- - `BackendError.NotFound(message: string)` // 404, showUser: true
87
- - `BackendError.Conflict(message: string)` // 409, showUser: true
88
- - `BackendError.UnprocessableEntity(message: string)`// 422, showUser: true
89
- - `BackendError.Internal(message: string)` // 500, showUser: false
90
- - `BackendError.ServiceUnavailable(message: string)` // 503, showUser: false
108
+ ---
91
109
 
92
110
  ## 🧩 Types
93
111
 
94
112
  ```ts
95
113
  export type Severity = "info" | "warning" | "error" | "critical";
96
- ```
97
114
 
98
- ```ts
99
115
  export interface BackendErrorOptions {
100
116
  message: string;
101
117
  isOperational?: boolean;
@@ -106,14 +122,38 @@ export interface BackendErrorOptions {
106
122
  }
107
123
  ```
108
124
 
109
- > 💬 Tip: This package doesn't handle headers or CORS. If you're building an API for browsers, remember to configure CORS separately.
110
-
111
125
  ---
112
126
 
113
- ## 🌐 Repo
127
+ ## 🎨 Works well with [error-drawings](https://www.npmjs.com/package/error-drawings)
114
128
 
115
- [https://github.com/eriksturesson/backendError](https://github.com/eriksturesson/backendError)
129
+ ![GitHub package.json version (master)](https://img.shields.io/github/package-json/v/eriksturesson/errorDrawings/master)
130
+ ![npm downloads](https://img.shields.io/npm/dy/error-drawings?label=npm%20downloads)
131
+
132
+ ```bash
133
+ npm install error-drawings
134
+ ```
135
+
136
+ Use for dev-friendly terminal logs — with a bit of dramatic flair for critical errors:
137
+
138
+ ```ts
139
+ import { BackendError, httpErrorFormatter } from "backend-error";
140
+ import drawLog from "error-drawings";
141
+
142
+ try {
143
+ throw BackendError.Forbidden("No access to resource");
144
+ } catch (err) {
145
+ const isCritical = !(err instanceof BackendError && err.isOperational) || err.code >= 500;
146
+ if (isCritical) drawLog(err); // Dramatic terminal art for critical errors!
147
+
148
+ const { status, body } = httpErrorFormatter(err);
149
+ res.status(status).json(body);
150
+ }
151
+ ```
116
152
 
117
153
  ---
118
154
 
155
+ ## 🌐 Repo
156
+
157
+ [GitHub](https://github.com/eriksturesson/backendError)
158
+
119
159
  Created by [@eriksturesson](https://eriksturesson.se)
@@ -1,8 +1,6 @@
1
- export declare function httpErrorFormatter({ err, }: {
2
- err: unknown;
3
- }): Promise<{
1
+ export declare function httpErrorFormatter(err: unknown): {
4
2
  status: number;
5
3
  body: Record<string, any>;
6
4
  showUser: boolean;
7
5
  message: string;
8
- }>;
6
+ };
@@ -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(_a) {
56
- var err = _a.err;
57
- return __awaiter(this, void 0, void 0, function () {
58
- var status_1, showUser_1, message_1, body_1, status, message, showUser, maybeStatus, body;
59
- return __generator(this, function (_b) {
60
- // Handle your custom BackendError type
61
- if (err instanceof BackendError_1.BackendError) {
62
- status_1 = isValidStatusCode(err.code) ? err.code : 400;
63
- showUser_1 = typeof err.showUser === "boolean" ? err.showUser : status_1 < 500;
64
- message_1 = err.message || "Error";
65
- body_1 = showUser_1
66
- ? __assign(__assign({ message: message_1 }, (err.data !== undefined && { data: err.data })), { code: status_1, severity: err.severity }) : { message: "Internal Server Error" };
67
- return [2 /*return*/, { status: status_1, body: body_1, showUser: showUser_1, message: message_1 }];
68
- }
69
- status = 500;
70
- message = "Internal Server Error";
71
- showUser = false;
72
- if (err instanceof Error) {
73
- message = err.message;
74
- maybeStatus = err.status || err.code;
75
- if (isValidStatusCode(maybeStatus)) {
76
- status = maybeStatus;
77
- showUser = status < 500; // show message for 4xx errors by default
78
- }
79
- }
80
- else if (typeof err === "string") {
81
- message = err;
82
- status = 400;
83
- showUser = true;
84
- }
85
- body = showUser ? { message: message } : { message: "Internal Server Error" };
86
- return [2 /*return*/, { status: status, body: body, showUser: showUser, message: message }];
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;
package/package.json CHANGED
@@ -1,6 +1,21 @@
1
1
  {
2
+ "version": "1.1.1",
2
3
  "name": "backend-error",
3
4
  "license": "MIT",
5
+ "keywords": [
6
+ "error",
7
+ "error-handler",
8
+ "http-errors",
9
+ "express",
10
+ "firebase-functions",
11
+ "nodejs",
12
+ "api",
13
+ "backend",
14
+ "error-handling",
15
+ "http-status",
16
+ "custom-error",
17
+ "structured-error"
18
+ ],
4
19
  "maintainers": [
5
20
  "Erik Sturesson"
6
21
  ],
@@ -9,17 +24,7 @@
9
24
  "email": "hej@eriksturesson.se",
10
25
  "url": "https://eriksturesson.se"
11
26
  },
12
- "version": "1.0.4",
13
27
  "description": "Simple Error handling library.",
14
- "keywords": [
15
- "error",
16
- "fail",
17
- "drawing",
18
- "drawings",
19
- "summarized",
20
- "help",
21
- "fun"
22
- ],
23
28
  "repository": {
24
29
  "type": "git",
25
30
  "url": "https://github.com/eriksturesson/backendError"