Simon
Simon4w ago

Throw Validation error inside the procedure?

Is there an easy way to throw a validation error programmatically from inside the procedure? I'm already pre-validating the input with a schema (Arktype) but then I need to add some additional validation to check uniqueness or other things with the DB or external API. What I'd like to do is being able to use something like this inside my procedure.
protectedProcedure
.input(
type({
url: type("string.url > 0").configure({
message: () => "URL is invalid.",
}),
}),
)
.mutation(async ({ ctx, input }) => {
const urlAlreadyExists = false // check against DB or API

type({
"url": type("true").configure({
message: "URL already exists.",
}),
}).assert({ "url": urlAlreadyExists });

// Do something with the URL
})
protectedProcedure
.input(
type({
url: type("string.url > 0").configure({
message: () => "URL is invalid.",
}),
}),
)
.mutation(async ({ ctx, input }) => {
const urlAlreadyExists = false // check against DB or API

type({
"url": type("true").configure({
message: "URL already exists.",
}),
}).assert({ "url": urlAlreadyExists });

// Do something with the URL
})
This throws an INTERNAL_SERVER_ERROR, so my current workaround is to catch the ArkError and wrap it into a TRPCError BAD_REQUEST. This feels kind of hacky, and I'd like to ensure this works as closely as the input validation as possible, so that my frontend can handle both cases similarly. In this case if the URL I send is invalid, it shows under the field. If the URL is valid, but it already exists or is banned or whatever, I want it so show under the field as well.
2 Replies
Nick
Nick4w ago
You’ll want an errorFormatter and to handle the error globally there
Simon
SimonOP4w ago
Yeah that's what I'm doing currently. Wraping into a TRPCError + errorFormatter that is already used for the input validation. Thought there would be an easier solution, but that's still fine enough:
export async function validate(
path: string,
condition: boolean | (() => Promise<boolean>),
message: string = "",
) {
try {
type({
[path]: type("true").configure({
message: message ?? "Invalid value.",
}),
}).assert({
[path]: typeof condition === "function" ? await condition() : condition,
});
} catch (e) {
throw new TRPCError({
code: "BAD_REQUEST",
cause: e,
});
}
}
export async function validate(
path: string,
condition: boolean | (() => Promise<boolean>),
message: string = "",
) {
try {
type({
[path]: type("true").configure({
message: message ?? "Invalid value.",
}),
}).assert({
[path]: typeof condition === "function" ? await condition() : condition,
});
} catch (e) {
throw new TRPCError({
code: "BAD_REQUEST",
cause: e,
});
}
}

Did you find this page helpful?