hono-ban 0.2.0 → 0.2.3

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
@@ -17,6 +17,7 @@ HTTP-friendly error objects for [Hono](https://hono.dev), inspired by [Boom](htt
17
17
  - [Custom Error Data](#custom-error-data)
18
18
  - [Error Conversion](#error-conversion)
19
19
  - [Error Formatting](#error-formatting)
20
+ - [OpenAPI Integration](#openapi-integration)
20
21
  - [Formatters](#formatters)
21
22
  - [Default Formatter](#default-formatter)
22
23
  - [RFC7807 (Problem Details) Formatter](#rfc7807-problem-details-formatter)
@@ -55,7 +56,14 @@ hono-ban provides a comprehensive error handling solution for Hono.js applicatio
55
56
  ### Basic Usage
56
57
 
57
58
  ```typescript
58
- import { notFound, badRequest } from "hono-ban";
59
+ import { Hono } from "hono";
60
+ import ban, { notFound, badRequest } from "hono-ban";
61
+
62
+ // Create a Hono app
63
+ const app = new Hono();
64
+
65
+ // IMPORTANT: Add the ban middleware for error handling to work
66
+ app.use(ban());
59
67
 
60
68
  // Create a 404 Not Found error
61
69
  const error = notFound("User not found");
@@ -66,10 +74,20 @@ const validationError = badRequest("Invalid input", {
66
74
  invalidFields: ["email", "password"],
67
75
  },
68
76
  });
77
+
78
+ // Example route that throws an error
79
+ app.get("/users/:id", (c) => {
80
+ // The thrown error will be caught and formatted by the ban middleware
81
+ throw notFound(`User with ID ${c.req.param("id")} not found`);
82
+ });
69
83
  ```
70
84
 
85
+ > **Note**: The ban middleware is required for errors to be automatically caught and formatted. Without it, thrown errors won't be properly handled.
86
+
71
87
  ### Error Middleware
72
88
 
89
+ The ban middleware is **required** to catch and format errors thrown in your routes. Without this middleware, errors will not be properly handled.
90
+
73
91
  #### Basic Usage
74
92
 
75
93
  ```typescript
@@ -80,6 +98,7 @@ import { notFound } from "hono-ban";
80
98
  const app = new Hono();
81
99
 
82
100
  // Add the error handling middleware with default options
101
+ // This is REQUIRED for error handling to work
83
102
  app.use(ban());
84
103
 
85
104
  // Routes can throw errors that will be handled automatically
@@ -189,6 +208,96 @@ const formatted = formatError(banError, myFormatter, {
189
208
  const response = createErrorResponse(banError, formatted);
190
209
  ```
191
210
 
211
+ ### OpenAPI Integration
212
+
213
+ hono-ban integrates seamlessly with [@hono/zod-openapi](https://github.com/honojs/middleware/tree/main/packages/zod-openapi) to provide standardized error handling for OpenAPI-validated routes.
214
+
215
+ ```typescript
216
+ import { OpenAPIHono } from "@hono/zod-openapi";
217
+ import { ban, createRFC7807Formatter, rfc7807Hook } from "hono-ban";
218
+ import { RFC7807DetailsSchema } from "hono-ban/formatters/rfc7807";
219
+ import { createRoute, z } from "@hono/zod-openapi";
220
+ import type { Context } from "hono";
221
+ import type { Env } from "./config/env";
222
+
223
+ // Create an OpenAPIHono instance with the RFC7807 hook for validation errors
224
+ const app = new OpenAPIHono<Env>({ defaultHook: rfc7807Hook });
225
+
226
+ // IMPORTANT: Add the ban middleware with RFC7807 formatter
227
+ app.use(
228
+ ban({
229
+ formatter: createRFC7807Formatter({
230
+ baseUrl: "https://api.example.com/errors",
231
+ }),
232
+ })
233
+ );
234
+
235
+ // Define a schema for your data
236
+ const NoteSchema = z.object({
237
+ name: z.string().max(10),
238
+ });
239
+
240
+ // Create an OpenAPI route with error handling
241
+ const route = createRoute({
242
+ method: "post",
243
+ path: "/notes",
244
+ request: {
245
+ body: {
246
+ content: {
247
+ "application/json": {
248
+ schema: NoteSchema,
249
+ },
250
+ },
251
+ required: true,
252
+ },
253
+ },
254
+ responses: {
255
+ 200: {
256
+ description: "Successfully created note",
257
+ content: {
258
+ "application/json": {
259
+ schema: z.object({
260
+ data: z.object({
261
+ id: z.string(),
262
+ type: z.string(),
263
+ attributes: NoteSchema,
264
+ }),
265
+ }),
266
+ },
267
+ },
268
+ },
269
+ 400: {
270
+ description: "Validation error",
271
+ content: {
272
+ "application/json": {
273
+ schema: RFC7807DetailsSchema, // Use the RFC7807 schema for errors
274
+ },
275
+ },
276
+ },
277
+ },
278
+ });
279
+
280
+ // Register the route
281
+ app.openapi(route, async (c) => {
282
+ // Handle the request
283
+ // Any validation errors will be automatically formatted using RFC7807
284
+ return c.json({
285
+ data: {
286
+ /* response data */
287
+ },
288
+ });
289
+ });
290
+ ```
291
+
292
+ #### Key Benefits
293
+
294
+ 1. **Automatic Validation Error Handling**: The `rfc7807Hook` automatically converts Zod validation errors to RFC7807 format.
295
+ 2. **Standardized Error Responses**: All errors follow the RFC7807 specification.
296
+ 3. **OpenAPI Documentation**: Error schemas are properly documented in your OpenAPI specification.
297
+ 4. **Type Safety**: Full TypeScript support for request and response validation.
298
+
299
+ > **Note**: The ban middleware is still required when using OpenAPI integration. The `rfc7807Hook` handles validation errors, but the middleware is needed to catch and format other errors.
300
+
192
301
  ## Formatters
193
302
 
194
303
  hono-ban includes several built-in formatters for common error response formats.
@@ -274,21 +383,7 @@ The RFC7807 formatter provides several helper functions:
274
383
  - `createValidationError(params)`: Create validation error data
275
384
  - `createZodValidationError(error)`: Convert Zod validation errors to RFC7807 format
276
385
  - `createConstraintViolation(name, reason, resource, constraint)`: Create constraint violation data
277
- - `createRFC7807Hook(options)`: Create a Hono hook for Zod OpenAPI validation
278
-
279
- ```typescript
280
- import { createRFC7807Hook } from "hono-ban/formatters/rfc7807";
281
- import { OpenAPIHono } from "@hono/zod-openapi";
282
-
283
- const app = new OpenAPIHono();
284
-
285
- // Add the RFC7807 hook for validation errors
286
- app.openapi(
287
- createRFC7807Hook({
288
- baseUrl: "https://api.example.com/problems",
289
- })
290
- );
291
- ```
386
+ - `createRFC7807Hook(options)`: Create a Hono hook for Zod OpenAPI validation (see [OpenAPI Integration](#openapi-integration) for usage)
292
387
 
293
388
  ## API Reference
294
389
 
package/dist/cjs/index.js CHANGED
@@ -69,13 +69,13 @@ __export(exports_src, {
69
69
  entityTooLarge: () => entityTooLarge,
70
70
  defaultFormatter: () => defaultFormatter,
71
71
  default: () => src_default,
72
- createZodValidationError: () => createZodValidationError,
73
- createValidationError: () => createValidationError,
72
+ createRFC7807ZodValidationError: () => createRFC7807ZodValidationError,
73
+ createRFC7807ValidationError: () => createRFC7807ValidationError,
74
74
  createRFC7807Hook: () => createRFC7807Hook,
75
75
  createRFC7807Formatter: () => createRFC7807Formatter,
76
+ createRFC7807ConstraintViolation: () => createRFC7807ConstraintViolation,
76
77
  createErrorResponse: () => createErrorResponse,
77
78
  createError: () => createError,
78
- createConstraintViolation: () => createConstraintViolation,
79
79
  convertToBanError: () => convertToBanError,
80
80
  conflict: () => conflict,
81
81
  clientTimeout: () => clientTimeout,
@@ -83,11 +83,11 @@ __export(exports_src, {
83
83
  badImplementation: () => badImplementation,
84
84
  badGateway: () => badGateway,
85
85
  badData: () => badData,
86
- ValidationParamSchema: () => ValidationParamSchema,
87
86
  STATUS_CODES: () => STATUS_CODES,
88
- ProblemErrorDataSchema: () => ProblemErrorDataSchema,
89
- ProblemDetailsSchema: () => ProblemDetailsSchema,
90
- ConstraintViolationSchema: () => ConstraintViolationSchema
87
+ RFC7807ValidationParamSchema: () => RFC7807ValidationParamSchema,
88
+ RFC7807ErrorDataSchema: () => RFC7807ErrorDataSchema,
89
+ RFC7807DetailsSchema: () => RFC7807DetailsSchema,
90
+ RFC7807ConstraintViolationSchema: () => RFC7807ConstraintViolationSchema
91
91
  });
92
92
  module.exports = __toCommonJS(exports_src);
93
93
 
@@ -282,28 +282,64 @@ var defaultFormatter = {
282
282
 
283
283
  // src/formatters/rfc7807/schemas.ts
284
284
  var import_zod_openapi = require("@hono/zod-openapi");
285
- var ValidationParamSchema = import_zod_openapi.z.object({
286
- name: import_zod_openapi.z.string(),
287
- reason: import_zod_openapi.z.string()
288
- }).openapi("ValidationParam");
289
- var ConstraintViolationSchema = import_zod_openapi.z.object({
290
- name: import_zod_openapi.z.string(),
291
- reason: import_zod_openapi.z.string(),
292
- resource: import_zod_openapi.z.string(),
293
- constraint: import_zod_openapi.z.string()
294
- }).openapi("ConstraintViolation");
295
- var ProblemErrorDataSchema = import_zod_openapi.z.object({
296
- "invalid-params": import_zod_openapi.z.array(ValidationParamSchema).optional(),
297
- violations: import_zod_openapi.z.array(ConstraintViolationSchema).optional()
285
+ var RFC7807ValidationParamSchema = import_zod_openapi.z.object({
286
+ name: import_zod_openapi.z.string().openapi({
287
+ example: "username",
288
+ description: "The field name that failed validation"
289
+ }),
290
+ reason: import_zod_openapi.z.string().openapi({
291
+ example: "String must contain at least 3 character(s)",
292
+ description: "The reason for validation failure"
293
+ })
298
294
  });
299
- var ProblemDetailsSchema = import_zod_openapi.z.object({
300
- type: import_zod_openapi.z.string().url(),
301
- title: import_zod_openapi.z.string(),
302
- status: import_zod_openapi.z.number().int().min(400).max(599),
303
- detail: import_zod_openapi.z.string(),
304
- instance: import_zod_openapi.z.string(),
305
- timestamp: import_zod_openapi.z.string().datetime()
306
- }).merge(ProblemErrorDataSchema).openapi("ProblemDetails");
295
+ var RFC7807ConstraintViolationSchema = import_zod_openapi.z.object({
296
+ name: import_zod_openapi.z.string().openapi({
297
+ example: "email",
298
+ description: "The field name that violated a constraint"
299
+ }),
300
+ reason: import_zod_openapi.z.string().openapi({
301
+ example: "Email already exists",
302
+ description: "The reason for the constraint violation"
303
+ }),
304
+ resource: import_zod_openapi.z.string().openapi({
305
+ example: "user",
306
+ description: "The resource type that contains the constraint"
307
+ }),
308
+ constraint: import_zod_openapi.z.string().openapi({
309
+ example: "unique",
310
+ description: "The type of constraint that was violated"
311
+ })
312
+ });
313
+ var RFC7807ErrorDataSchema = import_zod_openapi.z.object({
314
+ "invalid-params": import_zod_openapi.z.array(RFC7807ValidationParamSchema).optional(),
315
+ violations: import_zod_openapi.z.array(RFC7807ConstraintViolationSchema).optional()
316
+ });
317
+ var RFC7807DetailsSchema = import_zod_openapi.z.object({
318
+ type: import_zod_openapi.z.string().url().openapi({
319
+ example: "https://api.example.com/problems/validation-error",
320
+ description: "A URI reference that identifies the problem type"
321
+ }),
322
+ title: import_zod_openapi.z.string().openapi({
323
+ example: "Validation Failed",
324
+ description: "A short, human-readable summary of the problem type"
325
+ }),
326
+ status: import_zod_openapi.z.number().int().min(400).max(599).openapi({
327
+ example: 400,
328
+ description: "The HTTP status code"
329
+ }),
330
+ detail: import_zod_openapi.z.string().optional().openapi({
331
+ example: "The request contains invalid fields",
332
+ description: "A human-readable explanation specific to this occurrence of the problem"
333
+ }),
334
+ instance: import_zod_openapi.z.string().url().optional().openapi({
335
+ example: "urn:uuid:6b56944d-5e89-4b4d-9ca7-c1be3d1f0e3f",
336
+ description: "A URI reference that identifies the specific occurrence of the problem"
337
+ }),
338
+ timestamp: import_zod_openapi.z.string().datetime().optional().openapi({
339
+ example: "2025-02-26T12:34:56.789Z",
340
+ description: "When the error occurred"
341
+ })
342
+ }).merge(RFC7807ErrorDataSchema);
307
343
 
308
344
  // src/formatters/rfc7807/formatter.ts
309
345
  function createRFC7807Formatter(options = {}) {
@@ -320,37 +356,37 @@ function createRFC7807Formatter(options = {}) {
320
356
  timestamp: new Date().toISOString()
321
357
  };
322
358
  if (error.data?.["invalid-params"]) {
323
- return ProblemDetailsSchema.parse({
359
+ return RFC7807DetailsSchema.parse({
324
360
  ...base,
325
361
  "invalid-params": error.data["invalid-params"]
326
362
  });
327
363
  }
328
364
  if (error.data?.violations) {
329
- return ProblemDetailsSchema.parse({
365
+ return RFC7807DetailsSchema.parse({
330
366
  ...base,
331
367
  violations: error.data.violations
332
368
  });
333
369
  }
334
- return ProblemDetailsSchema.parse(base);
370
+ return RFC7807DetailsSchema.parse(base);
335
371
  }
336
372
  };
337
373
  }
338
- function createValidationError(params) {
374
+ function createRFC7807ValidationError(params) {
339
375
  return {
340
- "invalid-params": ValidationParamSchema.array().parse(params)
376
+ "invalid-params": RFC7807ValidationParamSchema.array().parse(params)
341
377
  };
342
378
  }
343
- function createZodValidationError(error) {
379
+ function createRFC7807ZodValidationError(error) {
344
380
  return {
345
- "invalid-params": ValidationParamSchema.array().parse(error.errors.map((e) => ({
381
+ "invalid-params": RFC7807ValidationParamSchema.array().parse(error.errors.map((e) => ({
346
382
  name: e.path.join("."),
347
383
  reason: e.message
348
384
  })))
349
385
  };
350
386
  }
351
- function createConstraintViolation(name, reason, resource, constraint = "unique") {
387
+ function createRFC7807ConstraintViolation(name, reason, resource, constraint = "unique") {
352
388
  return {
353
- violations: ConstraintViolationSchema.array().parse([
389
+ violations: RFC7807ConstraintViolationSchema.array().parse([
354
390
  {
355
391
  name,
356
392
  reason,
@@ -4353,14 +4389,17 @@ function badImplementation(messageOrOptions, options) {
4353
4389
 
4354
4390
  // src/formatters/rfc7807/hooks.ts
4355
4391
  function createRFC7807Hook(options) {
4356
- const formatter = createRFC7807Formatter(options);
4357
4392
  return (result, c) => {
4358
4393
  if (!result.success && "error" in result && result.error instanceof ZodError) {
4359
- const error = badRequest("Validation Error", {
4360
- data: createZodValidationError(result.error)
4394
+ const validationData = createRFC7807ZodValidationError(result.error);
4395
+ throw badRequest({
4396
+ message: options?.message || "Validation Error",
4397
+ data: validationData,
4398
+ formatter: options?.formatter,
4399
+ headers: options?.headers,
4400
+ sanitize: options?.sanitize,
4401
+ includeStackTrace: options?.includeStackTrace
4361
4402
  });
4362
- const formatted = formatError(error, formatter);
4363
- return createErrorResponse(error, formatted);
4364
4403
  }
4365
4404
  };
4366
4405
  }
package/dist/esm/index.js CHANGED
@@ -189,28 +189,64 @@ var defaultFormatter = {
189
189
 
190
190
  // src/formatters/rfc7807/schemas.ts
191
191
  import { z } from "@hono/zod-openapi";
192
- var ValidationParamSchema = z.object({
193
- name: z.string(),
194
- reason: z.string()
195
- }).openapi("ValidationParam");
196
- var ConstraintViolationSchema = z.object({
197
- name: z.string(),
198
- reason: z.string(),
199
- resource: z.string(),
200
- constraint: z.string()
201
- }).openapi("ConstraintViolation");
202
- var ProblemErrorDataSchema = z.object({
203
- "invalid-params": z.array(ValidationParamSchema).optional(),
204
- violations: z.array(ConstraintViolationSchema).optional()
192
+ var RFC7807ValidationParamSchema = z.object({
193
+ name: z.string().openapi({
194
+ example: "username",
195
+ description: "The field name that failed validation"
196
+ }),
197
+ reason: z.string().openapi({
198
+ example: "String must contain at least 3 character(s)",
199
+ description: "The reason for validation failure"
200
+ })
205
201
  });
206
- var ProblemDetailsSchema = z.object({
207
- type: z.string().url(),
208
- title: z.string(),
209
- status: z.number().int().min(400).max(599),
210
- detail: z.string(),
211
- instance: z.string(),
212
- timestamp: z.string().datetime()
213
- }).merge(ProblemErrorDataSchema).openapi("ProblemDetails");
202
+ var RFC7807ConstraintViolationSchema = z.object({
203
+ name: z.string().openapi({
204
+ example: "email",
205
+ description: "The field name that violated a constraint"
206
+ }),
207
+ reason: z.string().openapi({
208
+ example: "Email already exists",
209
+ description: "The reason for the constraint violation"
210
+ }),
211
+ resource: z.string().openapi({
212
+ example: "user",
213
+ description: "The resource type that contains the constraint"
214
+ }),
215
+ constraint: z.string().openapi({
216
+ example: "unique",
217
+ description: "The type of constraint that was violated"
218
+ })
219
+ });
220
+ var RFC7807ErrorDataSchema = z.object({
221
+ "invalid-params": z.array(RFC7807ValidationParamSchema).optional(),
222
+ violations: z.array(RFC7807ConstraintViolationSchema).optional()
223
+ });
224
+ var RFC7807DetailsSchema = z.object({
225
+ type: z.string().url().openapi({
226
+ example: "https://api.example.com/problems/validation-error",
227
+ description: "A URI reference that identifies the problem type"
228
+ }),
229
+ title: z.string().openapi({
230
+ example: "Validation Failed",
231
+ description: "A short, human-readable summary of the problem type"
232
+ }),
233
+ status: z.number().int().min(400).max(599).openapi({
234
+ example: 400,
235
+ description: "The HTTP status code"
236
+ }),
237
+ detail: z.string().optional().openapi({
238
+ example: "The request contains invalid fields",
239
+ description: "A human-readable explanation specific to this occurrence of the problem"
240
+ }),
241
+ instance: z.string().url().optional().openapi({
242
+ example: "urn:uuid:6b56944d-5e89-4b4d-9ca7-c1be3d1f0e3f",
243
+ description: "A URI reference that identifies the specific occurrence of the problem"
244
+ }),
245
+ timestamp: z.string().datetime().optional().openapi({
246
+ example: "2025-02-26T12:34:56.789Z",
247
+ description: "When the error occurred"
248
+ })
249
+ }).merge(RFC7807ErrorDataSchema);
214
250
 
215
251
  // src/formatters/rfc7807/formatter.ts
216
252
  function createRFC7807Formatter(options = {}) {
@@ -227,37 +263,37 @@ function createRFC7807Formatter(options = {}) {
227
263
  timestamp: new Date().toISOString()
228
264
  };
229
265
  if (error.data?.["invalid-params"]) {
230
- return ProblemDetailsSchema.parse({
266
+ return RFC7807DetailsSchema.parse({
231
267
  ...base,
232
268
  "invalid-params": error.data["invalid-params"]
233
269
  });
234
270
  }
235
271
  if (error.data?.violations) {
236
- return ProblemDetailsSchema.parse({
272
+ return RFC7807DetailsSchema.parse({
237
273
  ...base,
238
274
  violations: error.data.violations
239
275
  });
240
276
  }
241
- return ProblemDetailsSchema.parse(base);
277
+ return RFC7807DetailsSchema.parse(base);
242
278
  }
243
279
  };
244
280
  }
245
- function createValidationError(params) {
281
+ function createRFC7807ValidationError(params) {
246
282
  return {
247
- "invalid-params": ValidationParamSchema.array().parse(params)
283
+ "invalid-params": RFC7807ValidationParamSchema.array().parse(params)
248
284
  };
249
285
  }
250
- function createZodValidationError(error) {
286
+ function createRFC7807ZodValidationError(error) {
251
287
  return {
252
- "invalid-params": ValidationParamSchema.array().parse(error.errors.map((e) => ({
288
+ "invalid-params": RFC7807ValidationParamSchema.array().parse(error.errors.map((e) => ({
253
289
  name: e.path.join("."),
254
290
  reason: e.message
255
291
  })))
256
292
  };
257
293
  }
258
- function createConstraintViolation(name, reason, resource, constraint = "unique") {
294
+ function createRFC7807ConstraintViolation(name, reason, resource, constraint = "unique") {
259
295
  return {
260
- violations: ConstraintViolationSchema.array().parse([
296
+ violations: RFC7807ConstraintViolationSchema.array().parse([
261
297
  {
262
298
  name,
263
299
  reason,
@@ -4260,14 +4296,17 @@ function badImplementation(messageOrOptions, options) {
4260
4296
 
4261
4297
  // src/formatters/rfc7807/hooks.ts
4262
4298
  function createRFC7807Hook(options) {
4263
- const formatter = createRFC7807Formatter(options);
4264
4299
  return (result, c) => {
4265
4300
  if (!result.success && "error" in result && result.error instanceof ZodError) {
4266
- const error = badRequest("Validation Error", {
4267
- data: createZodValidationError(result.error)
4301
+ const validationData = createRFC7807ZodValidationError(result.error);
4302
+ throw badRequest({
4303
+ message: options?.message || "Validation Error",
4304
+ data: validationData,
4305
+ formatter: options?.formatter,
4306
+ headers: options?.headers,
4307
+ sanitize: options?.sanitize,
4308
+ includeStackTrace: options?.includeStackTrace
4268
4309
  });
4269
- const formatted = formatError(error, formatter);
4270
- return createErrorResponse(error, formatted);
4271
4310
  }
4272
4311
  };
4273
4312
  }
@@ -4353,13 +4392,13 @@ export {
4353
4392
  entityTooLarge,
4354
4393
  defaultFormatter,
4355
4394
  src_default as default,
4356
- createZodValidationError,
4357
- createValidationError,
4395
+ createRFC7807ZodValidationError,
4396
+ createRFC7807ValidationError,
4358
4397
  createRFC7807Hook,
4359
4398
  createRFC7807Formatter,
4399
+ createRFC7807ConstraintViolation,
4360
4400
  createErrorResponse,
4361
4401
  createError,
4362
- createConstraintViolation,
4363
4402
  convertToBanError,
4364
4403
  conflict,
4365
4404
  clientTimeout,
@@ -4367,9 +4406,9 @@ export {
4367
4406
  badImplementation,
4368
4407
  badGateway,
4369
4408
  badData,
4370
- ValidationParamSchema,
4371
4409
  STATUS_CODES,
4372
- ProblemErrorDataSchema,
4373
- ProblemDetailsSchema,
4374
- ConstraintViolationSchema
4410
+ RFC7807ValidationParamSchema,
4411
+ RFC7807ErrorDataSchema,
4412
+ RFC7807DetailsSchema,
4413
+ RFC7807ConstraintViolationSchema
4375
4414
  };
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { z } from "@hono/zod-openapi";
6
6
  import type { ErrorFormatter } from "../../types";
7
- import type { ValidationParam, RFC7807FormatterOptions as RFC7807Options } from "../../types";
7
+ import type { RFC7807ValidationParam, RFC7807FormatterOptions as RFC7807Options } from "../../types";
8
8
  /**
9
9
  * Create an RFC 7807 Problem Details formatter
10
10
  */
@@ -12,7 +12,7 @@ export declare function createRFC7807Formatter(options?: RFC7807Options): ErrorF
12
12
  /**
13
13
  * Create validation error data in RFC 7807 format
14
14
  */
15
- export declare function createValidationError(params: ValidationParam[]): {
15
+ export declare function createRFC7807ValidationError(params: RFC7807ValidationParam[]): {
16
16
  "invalid-params": {
17
17
  name: string;
18
18
  reason: string;
@@ -21,7 +21,7 @@ export declare function createValidationError(params: ValidationParam[]): {
21
21
  /**
22
22
  * Convert Zod validation errors to RFC 7807 format
23
23
  */
24
- export declare function createZodValidationError(error: z.ZodError): {
24
+ export declare function createRFC7807ZodValidationError(error: z.ZodError): {
25
25
  "invalid-params": {
26
26
  name: string;
27
27
  reason: string;
@@ -30,7 +30,7 @@ export declare function createZodValidationError(error: z.ZodError): {
30
30
  /**
31
31
  * Create constraint violation data in RFC 7807 format
32
32
  */
33
- export declare function createConstraintViolation(name: string, reason: string, resource: string, constraint?: string): {
33
+ export declare function createRFC7807ConstraintViolation(name: string, reason: string, resource: string, constraint?: string): {
34
34
  violations: {
35
35
  name: string;
36
36
  reason: string;
@@ -4,12 +4,37 @@
4
4
  */
5
5
  import { Hook } from "@hono/zod-openapi";
6
6
  import { Env } from "hono";
7
- import type { RFC7807FormatterOptions as RFC7807Options } from "../../types";
7
+ import type { RFC7807FormatterOptions as RFC7807Options, BanOptions } from "../../types";
8
8
  /**
9
9
  * Create a Hono hook that formats validation errors using RFC 7807
10
+ *
11
+ * This hook throws a badRequest error that will be caught and processed by the ban middleware.
12
+ * You can provide options to override the default behavior of the middleware.
13
+ *
14
+ * @example
15
+ * // Basic usage - inherits all settings from middleware
16
+ * app.openapi(route, handler, { onError: createRFC7807Hook() });
17
+ *
18
+ * @example
19
+ * // With custom message
20
+ * app.openapi(route, handler, {
21
+ * onError: createRFC7807Hook({ message: "Custom validation error" })
22
+ * });
23
+ *
24
+ * @example
25
+ * // With custom formatter and sanitization
26
+ * app.openapi(route, handler, {
27
+ * onError: createRFC7807Hook({
28
+ * formatter: customFormatter,
29
+ * sanitize: ['password', 'token']
30
+ * })
31
+ * });
10
32
  */
11
- export declare function createRFC7807Hook(options?: RFC7807Options): Hook<any, Env, any, any>;
33
+ export declare function createRFC7807Hook<E extends Env = Env>(options?: RFC7807Options & Partial<BanOptions>): Hook<any, E, any, any>;
12
34
  /**
13
35
  * Pre-configured RFC 7807 hook with default options
36
+ *
37
+ * This is a convenience export that uses the default options.
38
+ * It will throw a badRequest error that will be caught and processed by the ban middleware.
14
39
  */
15
40
  export declare const rfc7807Hook: Hook<any, Env, any, any>;
@@ -2,6 +2,6 @@
2
2
  * RFC 7807 Problem Details implementation for Hono Ban
3
3
  * @module hono-ban/formatters/rfc7807
4
4
  */
5
- export { createRFC7807Formatter, createValidationError, createZodValidationError, createConstraintViolation, } from "./formatter";
5
+ export { createRFC7807Formatter, createRFC7807ValidationError, createRFC7807ZodValidationError, createRFC7807ConstraintViolation, } from "./formatter";
6
6
  export { createRFC7807Hook, rfc7807Hook } from "./hooks";
7
- export { ValidationParamSchema, ConstraintViolationSchema, ProblemErrorDataSchema, ProblemDetailsSchema, } from "./schemas";
7
+ export { RFC7807ValidationParamSchema, RFC7807ConstraintViolationSchema, RFC7807ErrorDataSchema, RFC7807DetailsSchema, } from "./schemas";
@@ -4,9 +4,9 @@
4
4
  */
5
5
  import { z } from "@hono/zod-openapi";
6
6
  /**
7
- * Schema for validation error parameters
7
+ * Schema for RFC 7807 validation error parameters
8
8
  */
9
- export declare const ValidationParamSchema: z.ZodObject<{
9
+ export declare const RFC7807ValidationParamSchema: z.ZodObject<{
10
10
  name: z.ZodString;
11
11
  reason: z.ZodString;
12
12
  }, "strip", z.ZodTypeAny, {
@@ -17,9 +17,9 @@ export declare const ValidationParamSchema: z.ZodObject<{
17
17
  reason: string;
18
18
  }>;
19
19
  /**
20
- * Schema for constraint violations
20
+ * Schema for RFC 7807 constraint violations
21
21
  */
22
- export declare const ConstraintViolationSchema: z.ZodObject<{
22
+ export declare const RFC7807ConstraintViolationSchema: z.ZodObject<{
23
23
  name: z.ZodString;
24
24
  reason: z.ZodString;
25
25
  resource: z.ZodString;
@@ -36,9 +36,9 @@ export declare const ConstraintViolationSchema: z.ZodObject<{
36
36
  constraint: string;
37
37
  }>;
38
38
  /**
39
- * Schema for additional error data in problem details
39
+ * Schema for additional error data in RFC 7807 problem details
40
40
  */
41
- export declare const ProblemErrorDataSchema: z.ZodObject<{
41
+ export declare const RFC7807ErrorDataSchema: z.ZodObject<{
42
42
  "invalid-params": z.ZodOptional<z.ZodArray<z.ZodObject<{
43
43
  name: z.ZodString;
44
44
  reason: z.ZodString;
@@ -91,13 +91,13 @@ export declare const ProblemErrorDataSchema: z.ZodObject<{
91
91
  /**
92
92
  * Schema for complete RFC 7807 problem details
93
93
  */
94
- export declare const ProblemDetailsSchema: z.ZodObject<z.objectUtil.extendShape<{
94
+ export declare const RFC7807DetailsSchema: z.ZodObject<z.objectUtil.extendShape<{
95
95
  type: z.ZodString;
96
96
  title: z.ZodString;
97
97
  status: z.ZodNumber;
98
- detail: z.ZodString;
99
- instance: z.ZodString;
100
- timestamp: z.ZodString;
98
+ detail: z.ZodOptional<z.ZodString>;
99
+ instance: z.ZodOptional<z.ZodString>;
100
+ timestamp: z.ZodOptional<z.ZodString>;
101
101
  }, {
102
102
  "invalid-params": z.ZodOptional<z.ZodArray<z.ZodObject<{
103
103
  name: z.ZodString;
@@ -129,9 +129,6 @@ export declare const ProblemDetailsSchema: z.ZodObject<z.objectUtil.extendShape<
129
129
  type: string;
130
130
  title: string;
131
131
  status: number;
132
- detail: string;
133
- instance: string;
134
- timestamp: string;
135
132
  "invalid-params"?: {
136
133
  name: string;
137
134
  reason: string;
@@ -142,13 +139,13 @@ export declare const ProblemDetailsSchema: z.ZodObject<z.objectUtil.extendShape<
142
139
  resource: string;
143
140
  constraint: string;
144
141
  }[] | undefined;
142
+ detail?: string | undefined;
143
+ instance?: string | undefined;
144
+ timestamp?: string | undefined;
145
145
  }, {
146
146
  type: string;
147
147
  title: string;
148
148
  status: number;
149
- detail: string;
150
- instance: string;
151
- timestamp: string;
152
149
  "invalid-params"?: {
153
150
  name: string;
154
151
  reason: string;
@@ -159,4 +156,7 @@ export declare const ProblemDetailsSchema: z.ZodObject<z.objectUtil.extendShape<
159
156
  resource: string;
160
157
  constraint: string;
161
158
  }[] | undefined;
159
+ detail?: string | undefined;
160
+ instance?: string | undefined;
161
+ timestamp?: string | undefined;
162
162
  }>;
@@ -8,87 +8,70 @@
8
8
  * @module hono-ban/types/rfc7807
9
9
  * @see {@link https://datatracker.ietf.org/doc/html/rfc7807} RFC 7807 Problem Details
10
10
  */
11
+ import { z } from "@hono/zod-openapi";
12
+ import { RFC7807ValidationParamSchema, RFC7807ConstraintViolationSchema, RFC7807ErrorDataSchema, RFC7807DetailsSchema } from "../formatters/rfc7807/schemas";
11
13
  /**
12
14
  * Represents a validation error parameter in an RFC 7807 problem details object.
13
15
  * Used to indicate specific validation failures in request parameters.
14
16
  *
15
- * @interface ValidationParam
17
+ * @type RFC7807ValidationParam
16
18
  * @property {string} name - The name of the parameter that failed validation
17
19
  * @property {string} reason - The reason why the parameter failed validation
18
20
  */
19
- export interface ValidationParam {
20
- name: string;
21
- reason: string;
22
- }
21
+ export type RFC7807ValidationParam = z.infer<typeof RFC7807ValidationParamSchema>;
23
22
  /**
24
23
  * Represents a constraint violation in an RFC 7807 problem details object.
25
24
  * Used to indicate violations of business rules or data constraints.
26
25
  *
27
- * @interface ConstraintViolation
26
+ * @type RFC7807ConstraintViolation
28
27
  * @property {string} name - The name of the violated constraint
29
28
  * @property {string} reason - The reason why the constraint was violated
30
29
  * @property {string} resource - The resource or entity where the violation occurred
31
30
  * @property {string} constraint - The specific constraint that was violated
32
31
  */
33
- export interface ConstraintViolation {
34
- name: string;
35
- reason: string;
36
- resource: string;
37
- constraint: string;
38
- }
32
+ export type RFC7807ConstraintViolation = z.infer<typeof RFC7807ConstraintViolationSchema>;
39
33
  /**
40
34
  * Additional error data that can be included in an RFC 7807 problem details object.
41
35
  * This interface extends the standard problem details with validation and constraint information.
42
36
  *
43
- * @interface ProblemErrorData
44
- * @property {ValidationParam[]} [invalid-params] - Array of validation errors
45
- * @property {ConstraintViolation[]} [violations] - Array of constraint violations
37
+ * @type RFC7807ErrorData
38
+ * @property {RFC7807ValidationParam[]} [invalid-params] - Array of validation errors
39
+ * @property {RFC7807ConstraintViolation[]} [violations] - Array of constraint violations
46
40
  */
47
- export interface ProblemErrorData {
48
- "invalid-params"?: ValidationParam[];
49
- violations?: ConstraintViolation[];
50
- }
41
+ export type RFC7807ErrorData = z.infer<typeof RFC7807ErrorDataSchema>;
51
42
  /**
52
43
  * Complete RFC 7807 problem details object structure.
53
44
  * This interface represents the full problem details format as defined in RFC 7807,
54
45
  * with additional properties for validation and constraint violation data.
55
46
  *
56
- * @interface ProblemDetails
57
- * @extends ProblemErrorData
47
+ * @type RFC7807Details
58
48
  * @property {string} type - URI reference that identifies the problem type
59
49
  * @property {string} title - Short, human-readable summary of the problem
60
50
  * @property {number} status - HTTP status code (400-599)
61
- * @property {string} detail - Human-readable explanation specific to this occurrence
62
- * @property {string} instance - URI reference that identifies the specific occurrence
63
- * @property {string} timestamp - ISO 8601 datetime when the error occurred
51
+ * @property {string} [detail] - Human-readable explanation specific to this occurrence
52
+ * @property {string} [instance] - URI reference that identifies the specific occurrence
53
+ * @property {string} [timestamp] - ISO 8601 datetime when the error occurred
64
54
  */
65
- export interface ProblemDetails extends ProblemErrorData {
66
- type: string;
67
- title: string;
68
- status: number;
69
- detail: string;
70
- instance: string;
71
- timestamp: string;
72
- }
55
+ export type RFC7807Details = z.infer<typeof RFC7807DetailsSchema>;
73
56
  /**
74
57
  * Hook function for customizing RFC 7807 problem details before formatting.
75
58
  * This type represents a function that can modify the problem details object
76
59
  * before it is serialized into the final response.
77
60
  *
78
- * @callback ProblemDetailsHook
79
- * @param {ProblemDetails} details - The problem details object to modify
80
- * @returns {ProblemDetails} The modified problem details object
61
+ * @callback RFC7807DetailsHook
62
+ * @param {RFC7807Details} details - The problem details object to modify
63
+ * @returns {RFC7807Details} The modified problem details object
81
64
  */
82
- export type ProblemDetailsHook = (details: ProblemDetails) => ProblemDetails;
65
+ export type RFC7807DetailsHook = (details: RFC7807Details) => RFC7807Details;
83
66
  /**
84
67
  * Configuration options for the RFC 7807 formatter.
85
68
  * These options control how problem details are generated and formatted.
86
69
  *
87
70
  * @interface RFC7807FormatterOptions
88
71
  * @property {string} [baseUrl="https://api.example.com/problems"] - Base URL for problem type URIs
89
- * @property {ProblemDetailsHook[]} [hooks=[]] - Array of hooks for customizing problem details
72
+ * @property {RFC7807DetailsHook[]} [hooks=[]] - Array of hooks for customizing problem details
90
73
  */
91
74
  export interface RFC7807FormatterOptions {
92
75
  baseUrl?: string;
93
- hooks?: ProblemDetailsHook[];
76
+ hooks?: RFC7807DetailsHook[];
94
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono-ban",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "description": "HTTP-friendly error objects for Hono, inspired by Boom",
5
5
  "type": "module",
6
6
  "main": "dist/cjs/index.js",
@@ -7,15 +7,15 @@ import { z } from "@hono/zod-openapi";
7
7
  import { STATUS_CODES } from "../../constants";
8
8
  import type { BanError, ErrorFormatter } from "../../types";
9
9
  import type {
10
- ProblemDetails,
11
- ProblemErrorData,
12
- ValidationParam,
10
+ RFC7807Details,
11
+ RFC7807ErrorData,
12
+ RFC7807ValidationParam,
13
13
  RFC7807FormatterOptions as RFC7807Options,
14
14
  } from "../../types";
15
15
  import {
16
- ConstraintViolationSchema,
17
- ProblemDetailsSchema,
18
- ValidationParamSchema,
16
+ RFC7807ConstraintViolationSchema,
17
+ RFC7807DetailsSchema,
18
+ RFC7807ValidationParamSchema,
19
19
  } from "./schemas";
20
20
 
21
21
  /**
@@ -29,7 +29,7 @@ export function createRFC7807Formatter(
29
29
  return {
30
30
  contentType: "application/problem+json",
31
31
 
32
- format<T extends ProblemErrorData>(error: BanError<T>): ProblemDetails {
32
+ format<T extends RFC7807ErrorData>(error: BanError<T>): RFC7807Details {
33
33
  const base = {
34
34
  type: `${baseUrl}/${error.status}`,
35
35
  title: STATUS_CODES[error.status] || "Unknown Error",
@@ -41,7 +41,7 @@ export function createRFC7807Formatter(
41
41
 
42
42
  // Handle validation errors
43
43
  if (error.data?.["invalid-params"]) {
44
- return ProblemDetailsSchema.parse({
44
+ return RFC7807DetailsSchema.parse({
45
45
  ...base,
46
46
  "invalid-params": error.data["invalid-params"],
47
47
  });
@@ -49,13 +49,13 @@ export function createRFC7807Formatter(
49
49
 
50
50
  // Handle constraint violations
51
51
  if (error.data?.violations) {
52
- return ProblemDetailsSchema.parse({
52
+ return RFC7807DetailsSchema.parse({
53
53
  ...base,
54
54
  violations: error.data.violations,
55
55
  });
56
56
  }
57
57
 
58
- return ProblemDetailsSchema.parse(base);
58
+ return RFC7807DetailsSchema.parse(base);
59
59
  },
60
60
  };
61
61
  }
@@ -63,18 +63,18 @@ export function createRFC7807Formatter(
63
63
  /**
64
64
  * Create validation error data in RFC 7807 format
65
65
  */
66
- export function createValidationError(params: ValidationParam[]) {
66
+ export function createRFC7807ValidationError(params: RFC7807ValidationParam[]) {
67
67
  return {
68
- "invalid-params": ValidationParamSchema.array().parse(params),
68
+ "invalid-params": RFC7807ValidationParamSchema.array().parse(params),
69
69
  };
70
70
  }
71
71
 
72
72
  /**
73
73
  * Convert Zod validation errors to RFC 7807 format
74
74
  */
75
- export function createZodValidationError(error: z.ZodError) {
75
+ export function createRFC7807ZodValidationError(error: z.ZodError) {
76
76
  return {
77
- "invalid-params": ValidationParamSchema.array().parse(
77
+ "invalid-params": RFC7807ValidationParamSchema.array().parse(
78
78
  error.errors.map((e) => ({
79
79
  name: e.path.join("."),
80
80
  reason: e.message,
@@ -86,14 +86,14 @@ export function createZodValidationError(error: z.ZodError) {
86
86
  /**
87
87
  * Create constraint violation data in RFC 7807 format
88
88
  */
89
- export function createConstraintViolation(
89
+ export function createRFC7807ConstraintViolation(
90
90
  name: string,
91
91
  reason: string,
92
92
  resource: string,
93
93
  constraint: string = "unique"
94
94
  ) {
95
95
  return {
96
- violations: ConstraintViolationSchema.array().parse([
96
+ violations: RFC7807ConstraintViolationSchema.array().parse([
97
97
  {
98
98
  name,
99
99
  reason,
@@ -7,41 +7,67 @@ import { ZodError } from "zod";
7
7
  import { Hook } from "@hono/zod-openapi";
8
8
  import { Env } from "hono";
9
9
  import { badRequest } from "../../factories";
10
- import { formatError, createErrorResponse } from "../../core";
11
- import type { RFC7807FormatterOptions as RFC7807Options } from "../../types";
12
-
13
- import { createRFC7807Formatter } from "./formatter";
14
- import { createZodValidationError } from "./formatter";
10
+ import type {
11
+ RFC7807FormatterOptions as RFC7807Options,
12
+ BanOptions,
13
+ } from "../../types";
14
+ import { createRFC7807ZodValidationError } from "./formatter";
15
15
 
16
16
  /**
17
17
  * Create a Hono hook that formats validation errors using RFC 7807
18
+ *
19
+ * This hook throws a badRequest error that will be caught and processed by the ban middleware.
20
+ * You can provide options to override the default behavior of the middleware.
21
+ *
22
+ * @example
23
+ * // Basic usage - inherits all settings from middleware
24
+ * app.openapi(route, handler, { onError: createRFC7807Hook() });
25
+ *
26
+ * @example
27
+ * // With custom message
28
+ * app.openapi(route, handler, {
29
+ * onError: createRFC7807Hook({ message: "Custom validation error" })
30
+ * });
31
+ *
32
+ * @example
33
+ * // With custom formatter and sanitization
34
+ * app.openapi(route, handler, {
35
+ * onError: createRFC7807Hook({
36
+ * formatter: customFormatter,
37
+ * sanitize: ['password', 'token']
38
+ * })
39
+ * });
18
40
  */
19
- export function createRFC7807Hook(
20
- options?: RFC7807Options
21
- ): Hook<any, Env, any, any> {
22
- const formatter = createRFC7807Formatter(options);
23
-
41
+ export function createRFC7807Hook<E extends Env = Env>(
42
+ options?: RFC7807Options & Partial<BanOptions>
43
+ ): Hook<any, E, any, any> {
24
44
  return (result, c) => {
25
45
  if (
26
46
  !result.success &&
27
47
  "error" in result &&
28
48
  result.error instanceof ZodError
29
49
  ) {
30
- // Create the error
31
- const error = badRequest("Validation Error", {
32
- data: createZodValidationError(result.error),
33
- });
50
+ // Create the validation error data
51
+ const validationData = createRFC7807ZodValidationError(result.error);
34
52
 
35
- // Format the error using RFC7807
36
- const formatted = formatError(error, formatter);
37
-
38
- // Create and return the response
39
- return createErrorResponse(error, formatted);
53
+ // Throw badRequest with both the validation data and any override options
54
+ throw badRequest({
55
+ message: options?.message || "Validation Error",
56
+ data: validationData,
57
+ // Pass through any override options
58
+ formatter: options?.formatter,
59
+ headers: options?.headers,
60
+ sanitize: options?.sanitize,
61
+ includeStackTrace: options?.includeStackTrace,
62
+ });
40
63
  }
41
64
  };
42
65
  }
43
66
 
44
67
  /**
45
68
  * Pre-configured RFC 7807 hook with default options
69
+ *
70
+ * This is a convenience export that uses the default options.
71
+ * It will throw a badRequest error that will be caught and processed by the ban middleware.
46
72
  */
47
- export const rfc7807Hook = createRFC7807Hook();
73
+ export const rfc7807Hook = createRFC7807Hook<Env>();
@@ -5,16 +5,16 @@
5
5
 
6
6
  export {
7
7
  createRFC7807Formatter,
8
- createValidationError,
9
- createZodValidationError,
10
- createConstraintViolation,
8
+ createRFC7807ValidationError,
9
+ createRFC7807ZodValidationError,
10
+ createRFC7807ConstraintViolation,
11
11
  } from "./formatter";
12
12
 
13
13
  export { createRFC7807Hook, rfc7807Hook } from "./hooks";
14
14
 
15
15
  export {
16
- ValidationParamSchema,
17
- ConstraintViolationSchema,
18
- ProblemErrorDataSchema,
19
- ProblemDetailsSchema,
16
+ RFC7807ValidationParamSchema,
17
+ RFC7807ConstraintViolationSchema,
18
+ RFC7807ErrorDataSchema,
19
+ RFC7807DetailsSchema,
20
20
  } from "./schemas";
@@ -4,54 +4,85 @@
4
4
  */
5
5
 
6
6
  import { z } from "@hono/zod-openapi";
7
- import type {
8
- ValidationParam,
9
- ConstraintViolation,
10
- ProblemDetails,
11
- ProblemErrorData,
12
- } from "../../types";
13
7
 
14
8
  /**
15
- * Schema for validation error parameters
9
+ * Schema for RFC 7807 validation error parameters
16
10
  */
17
- export const ValidationParamSchema = z
18
- .object({
19
- name: z.string(),
20
- reason: z.string(),
21
- })
22
- .openapi("ValidationParam");
11
+ export const RFC7807ValidationParamSchema = z.object({
12
+ name: z.string().openapi({
13
+ example: "username",
14
+ description: "The field name that failed validation",
15
+ }),
16
+ reason: z.string().openapi({
17
+ example: "String must contain at least 3 character(s)",
18
+ description: "The reason for validation failure",
19
+ }),
20
+ });
23
21
 
24
22
  /**
25
- * Schema for constraint violations
23
+ * Schema for RFC 7807 constraint violations
26
24
  */
27
- export const ConstraintViolationSchema = z
28
- .object({
29
- name: z.string(),
30
- reason: z.string(),
31
- resource: z.string(),
32
- constraint: z.string(),
33
- })
34
- .openapi("ConstraintViolation");
25
+ export const RFC7807ConstraintViolationSchema = z.object({
26
+ name: z.string().openapi({
27
+ example: "email",
28
+ description: "The field name that violated a constraint",
29
+ }),
30
+ reason: z.string().openapi({
31
+ example: "Email already exists",
32
+ description: "The reason for the constraint violation",
33
+ }),
34
+ resource: z.string().openapi({
35
+ example: "user",
36
+ description: "The resource type that contains the constraint",
37
+ }),
38
+ constraint: z.string().openapi({
39
+ example: "unique",
40
+ description: "The type of constraint that was violated",
41
+ }),
42
+ });
35
43
 
36
44
  /**
37
- * Schema for additional error data in problem details
45
+ * Schema for additional error data in RFC 7807 problem details
38
46
  */
39
- export const ProblemErrorDataSchema = z.object({
40
- "invalid-params": z.array(ValidationParamSchema).optional(),
41
- violations: z.array(ConstraintViolationSchema).optional(),
47
+ export const RFC7807ErrorDataSchema = z.object({
48
+ "invalid-params": z.array(RFC7807ValidationParamSchema).optional(),
49
+ violations: z.array(RFC7807ConstraintViolationSchema).optional(),
42
50
  });
43
51
 
44
52
  /**
45
53
  * Schema for complete RFC 7807 problem details
46
54
  */
47
- export const ProblemDetailsSchema = z
55
+ export const RFC7807DetailsSchema = z
48
56
  .object({
49
- type: z.string().url(),
50
- title: z.string(),
51
- status: z.number().int().min(400).max(599),
52
- detail: z.string(),
53
- instance: z.string(),
54
- timestamp: z.string().datetime(),
57
+ type: z.string().url().openapi({
58
+ example: "https://api.example.com/problems/validation-error",
59
+ description: "A URI reference that identifies the problem type",
60
+ }),
61
+ title: z.string().openapi({
62
+ example: "Validation Failed",
63
+ description: "A short, human-readable summary of the problem type",
64
+ }),
65
+ status: z.number().int().min(400).max(599).openapi({
66
+ example: 400,
67
+ description: "The HTTP status code",
68
+ }),
69
+
70
+ // Optional fields per RFC7807
71
+ detail: z.string().optional().openapi({
72
+ example: "The request contains invalid fields",
73
+ description:
74
+ "A human-readable explanation specific to this occurrence of the problem",
75
+ }),
76
+ instance: z.string().url().optional().openapi({
77
+ example: "urn:uuid:6b56944d-5e89-4b4d-9ca7-c1be3d1f0e3f",
78
+ description:
79
+ "A URI reference that identifies the specific occurrence of the problem",
80
+ }),
81
+
82
+ // Extensions for validation errors
83
+ timestamp: z.string().datetime().optional().openapi({
84
+ example: "2025-02-26T12:34:56.789Z",
85
+ description: "When the error occurred",
86
+ }),
55
87
  })
56
- .merge(ProblemErrorDataSchema)
57
- .openapi("ProblemDetails");
88
+ .merge(RFC7807ErrorDataSchema);
@@ -9,82 +9,75 @@
9
9
  * @see {@link https://datatracker.ietf.org/doc/html/rfc7807} RFC 7807 Problem Details
10
10
  */
11
11
 
12
+ import { z } from "@hono/zod-openapi";
13
+ import {
14
+ RFC7807ValidationParamSchema,
15
+ RFC7807ConstraintViolationSchema,
16
+ RFC7807ErrorDataSchema,
17
+ RFC7807DetailsSchema,
18
+ } from "../formatters/rfc7807/schemas";
19
+
12
20
  /**
13
21
  * Represents a validation error parameter in an RFC 7807 problem details object.
14
22
  * Used to indicate specific validation failures in request parameters.
15
23
  *
16
- * @interface ValidationParam
24
+ * @type RFC7807ValidationParam
17
25
  * @property {string} name - The name of the parameter that failed validation
18
26
  * @property {string} reason - The reason why the parameter failed validation
19
27
  */
20
- export interface ValidationParam {
21
- name: string;
22
- reason: string;
23
- }
28
+ export type RFC7807ValidationParam = z.infer<
29
+ typeof RFC7807ValidationParamSchema
30
+ >;
24
31
 
25
32
  /**
26
33
  * Represents a constraint violation in an RFC 7807 problem details object.
27
34
  * Used to indicate violations of business rules or data constraints.
28
35
  *
29
- * @interface ConstraintViolation
36
+ * @type RFC7807ConstraintViolation
30
37
  * @property {string} name - The name of the violated constraint
31
38
  * @property {string} reason - The reason why the constraint was violated
32
39
  * @property {string} resource - The resource or entity where the violation occurred
33
40
  * @property {string} constraint - The specific constraint that was violated
34
41
  */
35
- export interface ConstraintViolation {
36
- name: string;
37
- reason: string;
38
- resource: string;
39
- constraint: string;
40
- }
42
+ export type RFC7807ConstraintViolation = z.infer<
43
+ typeof RFC7807ConstraintViolationSchema
44
+ >;
41
45
 
42
46
  /**
43
47
  * Additional error data that can be included in an RFC 7807 problem details object.
44
48
  * This interface extends the standard problem details with validation and constraint information.
45
49
  *
46
- * @interface ProblemErrorData
47
- * @property {ValidationParam[]} [invalid-params] - Array of validation errors
48
- * @property {ConstraintViolation[]} [violations] - Array of constraint violations
50
+ * @type RFC7807ErrorData
51
+ * @property {RFC7807ValidationParam[]} [invalid-params] - Array of validation errors
52
+ * @property {RFC7807ConstraintViolation[]} [violations] - Array of constraint violations
49
53
  */
50
- export interface ProblemErrorData {
51
- "invalid-params"?: ValidationParam[];
52
- violations?: ConstraintViolation[];
53
- }
54
+ export type RFC7807ErrorData = z.infer<typeof RFC7807ErrorDataSchema>;
54
55
 
55
56
  /**
56
57
  * Complete RFC 7807 problem details object structure.
57
58
  * This interface represents the full problem details format as defined in RFC 7807,
58
59
  * with additional properties for validation and constraint violation data.
59
60
  *
60
- * @interface ProblemDetails
61
- * @extends ProblemErrorData
61
+ * @type RFC7807Details
62
62
  * @property {string} type - URI reference that identifies the problem type
63
63
  * @property {string} title - Short, human-readable summary of the problem
64
64
  * @property {number} status - HTTP status code (400-599)
65
- * @property {string} detail - Human-readable explanation specific to this occurrence
66
- * @property {string} instance - URI reference that identifies the specific occurrence
67
- * @property {string} timestamp - ISO 8601 datetime when the error occurred
65
+ * @property {string} [detail] - Human-readable explanation specific to this occurrence
66
+ * @property {string} [instance] - URI reference that identifies the specific occurrence
67
+ * @property {string} [timestamp] - ISO 8601 datetime when the error occurred
68
68
  */
69
- export interface ProblemDetails extends ProblemErrorData {
70
- type: string;
71
- title: string;
72
- status: number;
73
- detail: string;
74
- instance: string;
75
- timestamp: string;
76
- }
69
+ export type RFC7807Details = z.infer<typeof RFC7807DetailsSchema>;
77
70
 
78
71
  /**
79
72
  * Hook function for customizing RFC 7807 problem details before formatting.
80
73
  * This type represents a function that can modify the problem details object
81
74
  * before it is serialized into the final response.
82
75
  *
83
- * @callback ProblemDetailsHook
84
- * @param {ProblemDetails} details - The problem details object to modify
85
- * @returns {ProblemDetails} The modified problem details object
76
+ * @callback RFC7807DetailsHook
77
+ * @param {RFC7807Details} details - The problem details object to modify
78
+ * @returns {RFC7807Details} The modified problem details object
86
79
  */
87
- export type ProblemDetailsHook = (details: ProblemDetails) => ProblemDetails;
80
+ export type RFC7807DetailsHook = (details: RFC7807Details) => RFC7807Details;
88
81
 
89
82
  /**
90
83
  * Configuration options for the RFC 7807 formatter.
@@ -92,9 +85,9 @@ export type ProblemDetailsHook = (details: ProblemDetails) => ProblemDetails;
92
85
  *
93
86
  * @interface RFC7807FormatterOptions
94
87
  * @property {string} [baseUrl="https://api.example.com/problems"] - Base URL for problem type URIs
95
- * @property {ProblemDetailsHook[]} [hooks=[]] - Array of hooks for customizing problem details
88
+ * @property {RFC7807DetailsHook[]} [hooks=[]] - Array of hooks for customizing problem details
96
89
  */
97
90
  export interface RFC7807FormatterOptions {
98
91
  baseUrl?: string;
99
- hooks?: ProblemDetailsHook[];
92
+ hooks?: RFC7807DetailsHook[];
100
93
  }