nexus-backend 1.0.6 → 1.0.8
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 +349 -349
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +35 -35
package/README.md
CHANGED
|
@@ -1,349 +1,349 @@
|
|
|
1
|
-
# Nexus Backend
|
|
2
|
-
|
|
3
|
-
A lightweight backend utility library for [Express.js](https://expressjs.com/) providing structured error classes, standardised API response helpers, and a plug-and-play error handling middleware.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Table of Contents
|
|
8
|
-
|
|
9
|
-
- [Installation](#installation)
|
|
10
|
-
- [Quick Start](#quick-start)
|
|
11
|
-
- [API Reference](#api-reference)
|
|
12
|
-
- [Response Helpers](#response-helpers)
|
|
13
|
-
- [Error Classes](#error-classes)
|
|
14
|
-
- [Error Middleware](#error-middleware)
|
|
15
|
-
- [Response Shape](#response-shape)
|
|
16
|
-
- [TypeScript](#typescript)
|
|
17
|
-
- [License](#license)
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Installation
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
|
|
25
|
-
npm install express mongoose cors helmet morgan cookie-parser
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Express, mongoose, cors, helmet, morgan, and cookie-parser are peer dependencies — make sure they are installed in your project:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install nexus-backend
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Quick Start
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
// src/config/mongoConfig.ts
|
|
40
|
-
import { type MongoConfig } from "nexus-backend";
|
|
41
|
-
|
|
42
|
-
const dbConfig: MongoConfig = {
|
|
43
|
-
subDomain: requiredEnv(process.env.DB_HOST, "DB_HOST"),
|
|
44
|
-
userName: requiredEnv(process.env.DB_USERNAME, "DB_USERNAME"),
|
|
45
|
-
password: requiredEnv(process.env.DB_PASSWORD, "DB_PASSWORD"),
|
|
46
|
-
cluster: requiredEnv(process.env.DB_CLUSTER, "DB_CLUSTER"),
|
|
47
|
-
dbName: requiredEnv(process.env.DB_NAME, "DB_NAME"),
|
|
48
|
-
};
|
|
49
|
-
export default dbConfig;
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
```ts
|
|
53
|
-
// src/server.ts
|
|
54
|
-
import express, { type Application, Request, Response } from "express";
|
|
55
|
-
import http from "http";
|
|
56
|
-
import {
|
|
57
|
-
successResponse,
|
|
58
|
-
errorMiddleware,
|
|
59
|
-
NotFoundError,
|
|
60
|
-
ValidationError,
|
|
61
|
-
} from "nexus-backend";
|
|
62
|
-
import cors from "cors";
|
|
63
|
-
import helmet from "helmet";
|
|
64
|
-
import morgan from "morgan";
|
|
65
|
-
import cookieParser from "cookie-parser";
|
|
66
|
-
import { Server } from "socket.io";
|
|
67
|
-
|
|
68
|
-
const app: Application = express();
|
|
69
|
-
|
|
70
|
-
if (process.env.NODE_ENV !== "production") {
|
|
71
|
-
app.use(morgan("dev"));
|
|
72
|
-
}
|
|
73
|
-
app.set("trust proxy", 1);
|
|
74
|
-
app.use(helmet());
|
|
75
|
-
app.use(
|
|
76
|
-
cors({
|
|
77
|
-
origin: process.env.FRONTEND_URL,
|
|
78
|
-
credentials: true,
|
|
79
|
-
}),
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
app.use(express.json({ limit: "500mb" })); // Adjust the limit as needed
|
|
83
|
-
app.use(express.urlencoded({ extended: true, limit: "500mb" })); // For parsing application/x-www-form-urlencoded
|
|
84
|
-
app.use(cookieParser());
|
|
85
|
-
|
|
86
|
-
// Example route
|
|
87
|
-
app.get("/users/:id", async (req: Request, res: Response) => {
|
|
88
|
-
const user = await getUserById(req.params.id);
|
|
89
|
-
|
|
90
|
-
if (!user) {
|
|
91
|
-
throw new NotFoundError("User not found");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
res.json(successResponse(user, "User fetched successfully"));
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Register error middleware last
|
|
98
|
-
app.use(errorMiddleware);
|
|
99
|
-
const server = http.createServer(app);
|
|
100
|
-
export const io = new Server(server, {
|
|
101
|
-
cors: {
|
|
102
|
-
origin: process.env.FRONTEND_URL,
|
|
103
|
-
credentials: true,
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
export default server;
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
// src/index.ts
|
|
112
|
-
import "dotenv/config";
|
|
113
|
-
import { connectMongoDb } from "nexus-backend";
|
|
114
|
-
import dns from "dns";
|
|
115
|
-
import dbConfig from "./config/mongoConfig";
|
|
116
|
-
import server from "./server";
|
|
117
|
-
const PORT = process.env.PORT || 5000;
|
|
118
|
-
async () => {
|
|
119
|
-
dns.setServers(["1.1.1.1", "1.0.0.1"]);
|
|
120
|
-
const dbConnected = await connectMongoDb(dbConfig);
|
|
121
|
-
if (!dbConnected) {
|
|
122
|
-
console.error("Database connection failed. Exiting...");
|
|
123
|
-
process.exit(1);
|
|
124
|
-
}
|
|
125
|
-
server.listen(PORT, () => {
|
|
126
|
-
console.log(`Server running on ${PORT}`);
|
|
127
|
-
});
|
|
128
|
-
};
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## API Reference
|
|
132
|
-
|
|
133
|
-
### Response Helpers
|
|
134
|
-
|
|
135
|
-
#### `successResponse(data, message?)`
|
|
136
|
-
|
|
137
|
-
Returns a structured success payload. Pass the result directly to `res.json()`.
|
|
138
|
-
|
|
139
|
-
```ts
|
|
140
|
-
successResponse<T>(data: T, message?: string): SuccessResponse<T>
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**Example**
|
|
144
|
-
|
|
145
|
-
```ts
|
|
146
|
-
res
|
|
147
|
-
.status(200)
|
|
148
|
-
.json(successResponse({ id: 1, name: "Alice" }, "User fetched successfully"));
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
```json
|
|
152
|
-
{
|
|
153
|
-
"success": true,
|
|
154
|
-
"message": "User fetched successfully",
|
|
155
|
-
"data": { "id": 1, "name": "Alice" }
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
#### `errorResponse(message, errors?, stack?)`
|
|
162
|
-
|
|
163
|
-
Returns a structured error payload. You will rarely call this directly — `errorMiddleware` calls it internally. Useful if you need to construct an error response manually.
|
|
164
|
-
|
|
165
|
-
```ts
|
|
166
|
-
errorResponse(message: string, errors?: any, stack?: string): ErrorResponse
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
**Example**
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
res
|
|
173
|
-
.status(400)
|
|
174
|
-
.json(
|
|
175
|
-
errorResponse("Validation failed", { field: "email", issue: "Required" }),
|
|
176
|
-
);
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
```json
|
|
180
|
-
{
|
|
181
|
-
"success": false,
|
|
182
|
-
"message": "Validation failed",
|
|
183
|
-
"errors": { "field": "email", "issue": "Required" }
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
### Error Classes
|
|
190
|
-
|
|
191
|
-
All error classes extend the base `ApiError` class, which itself extends the native `Error`. Throw any of these inside a route and let `errorMiddleware` handle the rest.
|
|
192
|
-
|
|
193
|
-
#### `ApiError`
|
|
194
|
-
|
|
195
|
-
The base error class. Use this when none of the specific subclasses fit your use case.
|
|
196
|
-
|
|
197
|
-
```ts
|
|
198
|
-
new ApiError(message: string, statusCode?: number, errors?: any, isOperational?: boolean)
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
| Parameter | Type | Default | Description |
|
|
202
|
-
| --------------- | --------- | ----------- | ------------------------------------------------ |
|
|
203
|
-
| `message` | `string` | — | Human-readable error message |
|
|
204
|
-
| `statusCode` | `number` | `500` | HTTP status code |
|
|
205
|
-
| `errors` | `any` | `undefined` | Additional error details or field errors |
|
|
206
|
-
| `isOperational` | `boolean` | `true` | Marks the error as an expected operational error |
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
#### `BadRequestError`
|
|
211
|
-
|
|
212
|
-
**Status:** `400 Bad Request`
|
|
213
|
-
|
|
214
|
-
Use when the client sends a malformed or invalid request.
|
|
215
|
-
|
|
216
|
-
```ts
|
|
217
|
-
throw new BadRequestError("Invalid request body");
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
#### `UnauthorizedError`
|
|
223
|
-
|
|
224
|
-
**Status:** `401 Unauthorized`
|
|
225
|
-
|
|
226
|
-
Use when authentication is missing or invalid.
|
|
227
|
-
|
|
228
|
-
```ts
|
|
229
|
-
throw new UnauthorizedError("Invalid token");
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
---
|
|
233
|
-
|
|
234
|
-
#### `ForbiddenError`
|
|
235
|
-
|
|
236
|
-
**Status:** `403 Forbidden`
|
|
237
|
-
|
|
238
|
-
Use when an authenticated user lacks permission to access a resource.
|
|
239
|
-
|
|
240
|
-
```ts
|
|
241
|
-
throw new ForbiddenError("You do not have access to this resource");
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
#### `NotFoundError`
|
|
247
|
-
|
|
248
|
-
**Status:** `404 Not Found`
|
|
249
|
-
|
|
250
|
-
Use when a requested resource does not exist.
|
|
251
|
-
|
|
252
|
-
```ts
|
|
253
|
-
throw new NotFoundError("Post not found");
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
---
|
|
257
|
-
|
|
258
|
-
#### `ValidationError`
|
|
259
|
-
|
|
260
|
-
**Status:** `422 Unprocessable Entity`
|
|
261
|
-
|
|
262
|
-
Use when request data fails validation. Pass field-level errors via the `errors` argument.
|
|
263
|
-
|
|
264
|
-
```ts
|
|
265
|
-
throw new ValidationError("Validation failed", [
|
|
266
|
-
{ field: "email", message: "Must be a valid email address" },
|
|
267
|
-
{ field: "password", message: "Must be at least 8 characters" },
|
|
268
|
-
]);
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
---
|
|
272
|
-
|
|
273
|
-
### Error Middleware
|
|
274
|
-
|
|
275
|
-
#### `errorMiddleware`
|
|
276
|
-
|
|
277
|
-
An Express-compatible error handling middleware. It catches any error passed to `next(err)`, determines the appropriate HTTP status code and message, and sends a structured `ErrorResponse`.
|
|
278
|
-
|
|
279
|
-
Register it **after all routes** and other middleware.
|
|
280
|
-
|
|
281
|
-
```ts
|
|
282
|
-
import { errorMiddleware } from "nexusjs";
|
|
283
|
-
|
|
284
|
-
app.use(errorMiddleware);
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
**Behaviour**
|
|
288
|
-
|
|
289
|
-
- If the error is an instance of `ApiError` (or any subclass), the middleware uses the error's own `statusCode` and `message`.
|
|
290
|
-
- For all other unhandled errors, it falls back to `500 Internal Server Error`.
|
|
291
|
-
- When `NODE_ENV` is set to `"development"`, the response includes a `stack` field with the full stack trace to aid debugging. The `stack` field is omitted in production.
|
|
292
|
-
|
|
293
|
-
**Development response example**
|
|
294
|
-
|
|
295
|
-
```json
|
|
296
|
-
{
|
|
297
|
-
"success": false,
|
|
298
|
-
"message": "User not found",
|
|
299
|
-
"errors": null,
|
|
300
|
-
"stack": "NotFoundError: User not found\n at ..."
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
---
|
|
305
|
-
|
|
306
|
-
## Response Shape
|
|
307
|
-
|
|
308
|
-
All responses follow a consistent structure.
|
|
309
|
-
|
|
310
|
-
#### Success
|
|
311
|
-
|
|
312
|
-
```ts
|
|
313
|
-
interface SuccessResponse<T> {
|
|
314
|
-
success: true;
|
|
315
|
-
message?: string;
|
|
316
|
-
data: T;
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
#### Error
|
|
321
|
-
|
|
322
|
-
```ts
|
|
323
|
-
interface ErrorResponse {
|
|
324
|
-
success: false;
|
|
325
|
-
message: string;
|
|
326
|
-
errors?: any;
|
|
327
|
-
stack?: string; // only present in development
|
|
328
|
-
}
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
---
|
|
332
|
-
|
|
333
|
-
## TypeScript
|
|
334
|
-
|
|
335
|
-
nexusjs is written in TypeScript and ships with type declarations out of the box. No `@types` package is needed.
|
|
336
|
-
|
|
337
|
-
`SuccessResponse` and `ErrorResponse` are exported and can be used to type your own response wrappers or API clients:
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
import type { SuccessResponse, ErrorResponse } from "nexusjs";
|
|
341
|
-
|
|
342
|
-
type ApiResult<T> = SuccessResponse<T> | ErrorResponse;
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
---
|
|
346
|
-
|
|
347
|
-
## License
|
|
348
|
-
|
|
349
|
-
MIT
|
|
1
|
+
# Nexus Backend
|
|
2
|
+
|
|
3
|
+
A lightweight backend utility library for [Express.js](https://expressjs.com/) providing structured error classes, standardised API response helpers, and a plug-and-play error handling middleware.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Quick Start](#quick-start)
|
|
11
|
+
- [API Reference](#api-reference)
|
|
12
|
+
- [Response Helpers](#response-helpers)
|
|
13
|
+
- [Error Classes](#error-classes)
|
|
14
|
+
- [Error Middleware](#error-middleware)
|
|
15
|
+
- [Response Shape](#response-shape)
|
|
16
|
+
- [TypeScript](#typescript)
|
|
17
|
+
- [License](#license)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
|
|
25
|
+
npm install express mongoose cors helmet morgan cookie-parser
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Express, mongoose, cors, helmet, morgan, and cookie-parser are peer dependencies — make sure they are installed in your project:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install nexus-backend
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// src/config/mongoConfig.ts
|
|
40
|
+
import { requiredEnv, type MongoConfig } from "nexus-backend";
|
|
41
|
+
|
|
42
|
+
const dbConfig: MongoConfig = {
|
|
43
|
+
subDomain: requiredEnv(process.env.DB_HOST, "DB_HOST"),
|
|
44
|
+
userName: requiredEnv(process.env.DB_USERNAME, "DB_USERNAME"),
|
|
45
|
+
password: requiredEnv(process.env.DB_PASSWORD, "DB_PASSWORD"),
|
|
46
|
+
cluster: requiredEnv(process.env.DB_CLUSTER, "DB_CLUSTER"),
|
|
47
|
+
dbName: requiredEnv(process.env.DB_NAME, "DB_NAME"),
|
|
48
|
+
};
|
|
49
|
+
export default dbConfig;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// src/server.ts
|
|
54
|
+
import express, { type Application, Request, Response } from "express";
|
|
55
|
+
import http from "http";
|
|
56
|
+
import {
|
|
57
|
+
successResponse,
|
|
58
|
+
errorMiddleware,
|
|
59
|
+
NotFoundError,
|
|
60
|
+
ValidationError,
|
|
61
|
+
} from "nexus-backend";
|
|
62
|
+
import cors from "cors";
|
|
63
|
+
import helmet from "helmet";
|
|
64
|
+
import morgan from "morgan";
|
|
65
|
+
import cookieParser from "cookie-parser";
|
|
66
|
+
import { Server } from "socket.io";
|
|
67
|
+
|
|
68
|
+
const app: Application = express();
|
|
69
|
+
|
|
70
|
+
if (process.env.NODE_ENV !== "production") {
|
|
71
|
+
app.use(morgan("dev"));
|
|
72
|
+
}
|
|
73
|
+
app.set("trust proxy", 1);
|
|
74
|
+
app.use(helmet());
|
|
75
|
+
app.use(
|
|
76
|
+
cors({
|
|
77
|
+
origin: process.env.FRONTEND_URL,
|
|
78
|
+
credentials: true,
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
app.use(express.json({ limit: "500mb" })); // Adjust the limit as needed
|
|
83
|
+
app.use(express.urlencoded({ extended: true, limit: "500mb" })); // For parsing application/x-www-form-urlencoded
|
|
84
|
+
app.use(cookieParser());
|
|
85
|
+
|
|
86
|
+
// Example route
|
|
87
|
+
app.get("/users/:id", async (req: Request, res: Response) => {
|
|
88
|
+
const user = await getUserById(req.params.id);
|
|
89
|
+
|
|
90
|
+
if (!user) {
|
|
91
|
+
throw new NotFoundError("User not found");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
res.json(successResponse(user, "User fetched successfully"));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Register error middleware last
|
|
98
|
+
app.use(errorMiddleware);
|
|
99
|
+
const server = http.createServer(app);
|
|
100
|
+
export const io = new Server(server, {
|
|
101
|
+
cors: {
|
|
102
|
+
origin: process.env.FRONTEND_URL,
|
|
103
|
+
credentials: true,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export default server;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
// src/index.ts
|
|
112
|
+
import "dotenv/config";
|
|
113
|
+
import { connectMongoDb } from "nexus-backend";
|
|
114
|
+
import dns from "dns";
|
|
115
|
+
import dbConfig from "./config/mongoConfig";
|
|
116
|
+
import server from "./server";
|
|
117
|
+
const PORT = process.env.PORT || 5000;
|
|
118
|
+
async () => {
|
|
119
|
+
dns.setServers(["1.1.1.1", "1.0.0.1"]);
|
|
120
|
+
const dbConnected = await connectMongoDb(dbConfig);
|
|
121
|
+
if (!dbConnected) {
|
|
122
|
+
console.error("Database connection failed. Exiting...");
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
server.listen(PORT, () => {
|
|
126
|
+
console.log(`Server running on ${PORT}`);
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## API Reference
|
|
132
|
+
|
|
133
|
+
### Response Helpers
|
|
134
|
+
|
|
135
|
+
#### `successResponse(data, message?)`
|
|
136
|
+
|
|
137
|
+
Returns a structured success payload. Pass the result directly to `res.json()`.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
successResponse<T>(data: T, message?: string): SuccessResponse<T>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Example**
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
res
|
|
147
|
+
.status(200)
|
|
148
|
+
.json(successResponse({ id: 1, name: "Alice" }, "User fetched successfully"));
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"success": true,
|
|
154
|
+
"message": "User fetched successfully",
|
|
155
|
+
"data": { "id": 1, "name": "Alice" }
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
#### `errorResponse(message, errors?, stack?)`
|
|
162
|
+
|
|
163
|
+
Returns a structured error payload. You will rarely call this directly — `errorMiddleware` calls it internally. Useful if you need to construct an error response manually.
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
errorResponse(message: string, errors?: any, stack?: string): ErrorResponse
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Example**
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
res
|
|
173
|
+
.status(400)
|
|
174
|
+
.json(
|
|
175
|
+
errorResponse("Validation failed", { field: "email", issue: "Required" }),
|
|
176
|
+
);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"success": false,
|
|
182
|
+
"message": "Validation failed",
|
|
183
|
+
"errors": { "field": "email", "issue": "Required" }
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Error Classes
|
|
190
|
+
|
|
191
|
+
All error classes extend the base `ApiError` class, which itself extends the native `Error`. Throw any of these inside a route and let `errorMiddleware` handle the rest.
|
|
192
|
+
|
|
193
|
+
#### `ApiError`
|
|
194
|
+
|
|
195
|
+
The base error class. Use this when none of the specific subclasses fit your use case.
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
new ApiError(message: string, statusCode?: number, errors?: any, isOperational?: boolean)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| Parameter | Type | Default | Description |
|
|
202
|
+
| --------------- | --------- | ----------- | ------------------------------------------------ |
|
|
203
|
+
| `message` | `string` | — | Human-readable error message |
|
|
204
|
+
| `statusCode` | `number` | `500` | HTTP status code |
|
|
205
|
+
| `errors` | `any` | `undefined` | Additional error details or field errors |
|
|
206
|
+
| `isOperational` | `boolean` | `true` | Marks the error as an expected operational error |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
#### `BadRequestError`
|
|
211
|
+
|
|
212
|
+
**Status:** `400 Bad Request`
|
|
213
|
+
|
|
214
|
+
Use when the client sends a malformed or invalid request.
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
throw new BadRequestError("Invalid request body");
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
#### `UnauthorizedError`
|
|
223
|
+
|
|
224
|
+
**Status:** `401 Unauthorized`
|
|
225
|
+
|
|
226
|
+
Use when authentication is missing or invalid.
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
throw new UnauthorizedError("Invalid token");
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
#### `ForbiddenError`
|
|
235
|
+
|
|
236
|
+
**Status:** `403 Forbidden`
|
|
237
|
+
|
|
238
|
+
Use when an authenticated user lacks permission to access a resource.
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
throw new ForbiddenError("You do not have access to this resource");
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
#### `NotFoundError`
|
|
247
|
+
|
|
248
|
+
**Status:** `404 Not Found`
|
|
249
|
+
|
|
250
|
+
Use when a requested resource does not exist.
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
throw new NotFoundError("Post not found");
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
#### `ValidationError`
|
|
259
|
+
|
|
260
|
+
**Status:** `422 Unprocessable Entity`
|
|
261
|
+
|
|
262
|
+
Use when request data fails validation. Pass field-level errors via the `errors` argument.
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
throw new ValidationError("Validation failed", [
|
|
266
|
+
{ field: "email", message: "Must be a valid email address" },
|
|
267
|
+
{ field: "password", message: "Must be at least 8 characters" },
|
|
268
|
+
]);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### Error Middleware
|
|
274
|
+
|
|
275
|
+
#### `errorMiddleware`
|
|
276
|
+
|
|
277
|
+
An Express-compatible error handling middleware. It catches any error passed to `next(err)`, determines the appropriate HTTP status code and message, and sends a structured `ErrorResponse`.
|
|
278
|
+
|
|
279
|
+
Register it **after all routes** and other middleware.
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
import { errorMiddleware } from "nexusjs";
|
|
283
|
+
|
|
284
|
+
app.use(errorMiddleware);
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Behaviour**
|
|
288
|
+
|
|
289
|
+
- If the error is an instance of `ApiError` (or any subclass), the middleware uses the error's own `statusCode` and `message`.
|
|
290
|
+
- For all other unhandled errors, it falls back to `500 Internal Server Error`.
|
|
291
|
+
- When `NODE_ENV` is set to `"development"`, the response includes a `stack` field with the full stack trace to aid debugging. The `stack` field is omitted in production.
|
|
292
|
+
|
|
293
|
+
**Development response example**
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"success": false,
|
|
298
|
+
"message": "User not found",
|
|
299
|
+
"errors": null,
|
|
300
|
+
"stack": "NotFoundError: User not found\n at ..."
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Response Shape
|
|
307
|
+
|
|
308
|
+
All responses follow a consistent structure.
|
|
309
|
+
|
|
310
|
+
#### Success
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
interface SuccessResponse<T> {
|
|
314
|
+
success: true;
|
|
315
|
+
message?: string;
|
|
316
|
+
data: T;
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
#### Error
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
interface ErrorResponse {
|
|
324
|
+
success: false;
|
|
325
|
+
message: string;
|
|
326
|
+
errors?: any;
|
|
327
|
+
stack?: string; // only present in development
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## TypeScript
|
|
334
|
+
|
|
335
|
+
nexusjs is written in TypeScript and ships with type declarations out of the box. No `@types` package is needed.
|
|
336
|
+
|
|
337
|
+
`SuccessResponse` and `ErrorResponse` are exported and can be used to type your own response wrappers or API clients:
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
import type { SuccessResponse, ErrorResponse } from "nexusjs";
|
|
341
|
+
|
|
342
|
+
type ApiResult<T> = SuccessResponse<T> | ErrorResponse;
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## License
|
|
348
|
+
|
|
349
|
+
MIT
|