Skip to content

Commit

Permalink
feat(validation-errors): support throwing validation errors via init …
Browse files Browse the repository at this point in the history
…option
  • Loading branch information
TheEdoRan committed Jun 20, 2024
1 parent 75e92f5 commit 769a372
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 3 deletions.
6 changes: 5 additions & 1 deletion packages/next-safe-action/src/action-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {
} from "./index.types";
import type { InferArray, InferInArray } from "./utils";
import { ActionMetadataError, DEFAULT_SERVER_ERROR_MESSAGE, isError, zodValidate } from "./utils";
import { buildValidationErrors } from "./validation-errors";
import { ActionValidationError, buildValidationErrors } from "./validation-errors";
import type {
BindArgsValidationErrors,
HandleBindArgsValidationErrorsShapeFn,
Expand Down Expand Up @@ -46,6 +46,7 @@ export function actionBuilder<
middlewareFns: MiddlewareFn<ServerError, any, any, any>[];
ctxType: Ctx;
validationStrategy: "typeschema" | "zod";
throwValidationErrors: boolean;
}) {
const bindArgsSchemas = (args.bindArgsSchemas ?? []) as BAS;

Expand Down Expand Up @@ -281,6 +282,9 @@ export function actionBuilder<
const actionResult: SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data> = {};

if (typeof middlewareResult.validationErrors !== "undefined") {
if (args.throwValidationErrors) {
throw new ActionValidationError(middlewareResult.validationErrors as CVE);
}
actionResult.validationErrors = middlewareResult.validationErrors as CVE;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/next-safe-action/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {

export { ActionMetadataError, DEFAULT_SERVER_ERROR_MESSAGE } from "./utils";
export {
ActionValidationError,
flattenBindArgsValidationErrors,
flattenValidationErrors,
formatBindArgsValidationErrors,
Expand Down Expand Up @@ -63,6 +64,7 @@ export const createSafeActionClient = <
metadataSchema: createOpts?.defineMetadataSchema?.(),
metadata: undefined as MetadataSchema extends Schema ? Infer<MetadataSchema> : undefined,
defaultValidationErrorsShape: (createOpts?.defaultValidationErrorsShape ?? "formatted") as ODVES,
throwValidationErrors: Boolean(createOpts?.throwValidationErrors),
handleValidationErrorsShape:
createOpts?.defaultValidationErrorsShape === "flattened" ? flattenValidationErrors : formatValidationErrors,
handleBindArgsValidationErrorsShape:
Expand Down
1 change: 1 addition & 0 deletions packages/next-safe-action/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type SafeActionClientOpts<
handleServerErrorLog?: (e: Error) => MaybePromise<void>;
handleReturnedServerError?: (e: Error) => MaybePromise<ServerError>;
defineMetadataSchema?: () => MetadataSchema;
throwValidationErrors?: boolean;
defaultValidationErrorsShape?: ODVES;
};

Expand Down
10 changes: 9 additions & 1 deletion packages/next-safe-action/src/safe-action-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export class SafeActionClient<
readonly #handleValidationErrorsShape: HandleValidationErrorsShapeFn<S, CVE>;
readonly #handleBindArgsValidationErrorsShape: HandleBindArgsValidationErrorsShapeFn<BAS, CBAVE>;
readonly #defaultValidationErrorsShape: ODVES;
readonly #throwValidationErrors: boolean;

constructor(
opts: {
Expand All @@ -59,7 +60,7 @@ export class SafeActionClient<
} & Required<
Pick<
SafeActionClientOpts<ServerError, any, ODVES>,
"handleReturnedServerError" | "handleServerErrorLog" | "defaultValidationErrorsShape"
"handleReturnedServerError" | "handleServerErrorLog" | "defaultValidationErrorsShape" | "throwValidationErrors"
>
>
) {
Expand All @@ -74,6 +75,7 @@ export class SafeActionClient<
this.#handleValidationErrorsShape = opts.handleValidationErrorsShape;
this.#handleBindArgsValidationErrorsShape = opts.handleBindArgsValidationErrorsShape;
this.#defaultValidationErrorsShape = opts.defaultValidationErrorsShape;
this.#throwValidationErrors = opts.throwValidationErrors;
}

/**
Expand All @@ -96,6 +98,7 @@ export class SafeActionClient<
handleBindArgsValidationErrorsShape: this.#handleBindArgsValidationErrorsShape,
ctxType: undefined as NextCtx,
defaultValidationErrorsShape: this.#defaultValidationErrorsShape,
throwValidationErrors: this.#throwValidationErrors,
});
}

Expand All @@ -119,6 +122,7 @@ export class SafeActionClient<
handleBindArgsValidationErrorsShape: this.#handleBindArgsValidationErrorsShape,
ctxType: undefined as Ctx,
defaultValidationErrorsShape: this.#defaultValidationErrorsShape,
throwValidationErrors: this.#throwValidationErrors,
});
}

Expand Down Expand Up @@ -160,6 +164,7 @@ export class SafeActionClient<
handleBindArgsValidationErrorsShape: this.#handleBindArgsValidationErrorsShape,
ctxType: undefined as Ctx,
defaultValidationErrorsShape: this.#defaultValidationErrorsShape,
throwValidationErrors: this.#throwValidationErrors,
});
}

Expand Down Expand Up @@ -193,6 +198,7 @@ export class SafeActionClient<
this.#handleBindArgsValidationErrorsShape) as HandleBindArgsValidationErrorsShapeFn<OBAS, OCBAVE>,
ctxType: undefined as Ctx,
defaultValidationErrorsShape: this.#defaultValidationErrorsShape,
throwValidationErrors: this.#throwValidationErrors,
});
}

Expand All @@ -219,6 +225,7 @@ export class SafeActionClient<
bindArgsSchemas: this.#bindArgsSchemas,
handleValidationErrorsShape: this.#handleValidationErrorsShape,
handleBindArgsValidationErrorsShape: this.#handleBindArgsValidationErrorsShape,
throwValidationErrors: this.#throwValidationErrors,
}).action(serverCodeFn, cb);
}

Expand Down Expand Up @@ -246,6 +253,7 @@ export class SafeActionClient<
bindArgsSchemas: this.#bindArgsSchemas,
handleValidationErrorsShape: this.#handleValidationErrorsShape,
handleBindArgsValidationErrorsShape: this.#handleBindArgsValidationErrorsShape,
throwValidationErrors: this.#throwValidationErrors,
}).stateAction(serverCodeFn, cb);
}
}
2 changes: 2 additions & 0 deletions packages/next-safe-action/src/typeschema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {

export { ActionMetadataError, DEFAULT_SERVER_ERROR_MESSAGE } from "./utils";
export {
ActionValidationError,
flattenBindArgsValidationErrors,
flattenValidationErrors,
formatBindArgsValidationErrors,
Expand Down Expand Up @@ -63,6 +64,7 @@ export const createSafeActionClient = <
metadataSchema: createOpts?.defineMetadataSchema?.(),
metadata: undefined as MetadataSchema extends Schema ? Infer<MetadataSchema> : undefined,
defaultValidationErrorsShape: (createOpts?.defaultValidationErrorsShape ?? "formatted") as ODVES,
throwValidationErrors: Boolean(createOpts?.throwValidationErrors),
handleValidationErrorsShape:
createOpts?.defaultValidationErrorsShape === "flattened" ? flattenValidationErrors : formatValidationErrors,
handleBindArgsValidationErrorsShape:
Expand Down
12 changes: 11 additions & 1 deletion packages/next-safe-action/src/validation-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,22 @@ export class ActionServerValidationError<S extends Schema> extends Error {
public kind: string;
public validationErrors: ValidationErrors<S>;
constructor(validationErrors: ValidationErrors<S>) {
super("Action server validation error");
super("Server Action server validation error(s) occurred");
this.validationErrors = validationErrors;
this.kind = "__actionServerValidationError";
}
}

// This class is internally used to throw validation errors in action's server code function, using
// `returnValidationErrors`.
export class ActionValidationError<CVE> extends Error {
public validationErrors: CVE;
constructor(validationErrors: CVE) {
super("Server Action validation error(s) occurred");
this.validationErrors = validationErrors;
}
}

/**
* Return custom validation errors to the client from the action's server code function.
* Code declared after this function invocation will not be executed.
Expand Down

0 comments on commit 769a372

Please sign in to comment.