@@ -14,10 +14,10 @@ import {
1414 type Method ,
1515} from "./context" ;
1616import type { CookieOptions , CookiePrefixOptions } from "./cookies" ;
17- import { APIError , type _statusCode , type Status } from "./error" ;
17+ import { APIError , ValidationError , type _statusCode , type Status } from "./error" ;
1818import type { OpenAPIParameter , OpenAPISchemaType } from "./openapi" ;
1919import type { StandardSchemaV1 } from "./standard-schema" ;
20- import { isAPIError } from "./utils" ;
20+ import { isAPIError , tryCatch } from "./utils" ;
2121
2222export interface EndpointOptions {
2323 /**
@@ -155,6 +155,14 @@ export interface EndpointOptions {
155155 * @returns - The response to return
156156 */
157157 onAPIError ?: ( e : APIError ) => void | Promise < void > ;
158+ /**
159+ * A callback to run before a validation error is thrown
160+ * You can customize the validation error message by throwing your own APIError
161+ */
162+ onValidationError ?: ( {
163+ issues,
164+ message,
165+ } : { message : string ; issues : readonly StandardSchemaV1 . Issue [ ] } ) => void | Promise < void > ;
158166}
159167
160168export type EndpointContext < Path extends string , Options extends EndpointOptions , Context = { } > = {
@@ -329,10 +337,31 @@ export const createEndpoint = <Path extends string, Options extends EndpointOpti
329337 : [ ( Context & { asResponse ?: AsResponse ; returnHeaders ?: ReturnHeaders } ) ?]
330338 ) => {
331339 const context = ( inputCtx [ 0 ] || { } ) as InputContext < any , any > ;
332- const internalContext = await createInternalContext ( context , {
333- options,
334- path,
335- } ) ;
340+ const { data : internalContext , error : validationError } = await tryCatch (
341+ createInternalContext ( context , {
342+ options,
343+ path,
344+ } ) ,
345+ ) ;
346+
347+ if ( validationError ) {
348+ // If it's not a validation error, we throw it
349+ if ( ! ( validationError instanceof ValidationError ) ) throw validationError ;
350+
351+ // Check if the endpoint has a custom onValidationError callback
352+ if ( options . onValidationError ) {
353+ // This can possibly throw an APIError in order to customize the validation error message
354+ await options . onValidationError ( {
355+ message : validationError . message ,
356+ issues : validationError . issues ,
357+ } ) ;
358+ }
359+
360+ throw new APIError ( 400 , {
361+ message : validationError . message ,
362+ code : "VALIDATION_ERROR" ,
363+ } ) ;
364+ }
336365 const response = await handler ( internalContext as any ) . catch ( async ( e ) => {
337366 if ( isAPIError ( e ) ) {
338367 const onAPIError = options . onAPIError ;
0 commit comments