y_nk
y_nk2w ago

sanitizing output based on output schema

As i understand, the .output will only ensure the schema is respected, but will not sanitize output on the go (even tho it could be possible with a z.strictObject()):
.output(someSchema) // <- does not sanitize data
// ---
.use(output(someSchema)) // <- should sanatize data

export function output<T extends ZodType>(schema: T) {
return middleware(async ({ next }) => {
const result = await next()
return schema.parse(result)
})
}
.output(someSchema) // <- does not sanitize data
// ---
.use(output(someSchema)) // <- should sanatize data

export function output<T extends ZodType>(schema: T) {
return middleware(async ({ next }) => {
const result = await next()
return schema.parse(result)
})
}
but for some reason the typing does not work. could somebody point out how to achieve similar but in a working way? is there no way to do what i want?
1 Reply
y_nk
y_nkOP2w ago
it's super ugly but it works:
import { TRPCError } from "@trpc/server";
import type { ZodType } from "zod";
import { middleware, procedure } from "../trpc";

export function output<T extends ZodType>(schema: T) {
return procedure.use(
middleware(async ({ next }) => {
const result = await next()

if (!result.ok) {
return result;
}

const parsed = schema.safeParse(result.data)

if (!parsed.success) {
return {
ok: false,
error: new TRPCError({ code: 'INTERNAL_SERVER_ERROR' }),
marker: result.marker,
}
}

return {
...result,
data: parsed.data
}
})
)
.output(schema)
}
import { TRPCError } from "@trpc/server";
import type { ZodType } from "zod";
import { middleware, procedure } from "../trpc";

export function output<T extends ZodType>(schema: T) {
return procedure.use(
middleware(async ({ next }) => {
const result = await next()

if (!result.ok) {
return result;
}

const parsed = schema.safeParse(result.data)

if (!parsed.success) {
return {
ok: false,
error: new TRPCError({ code: 'INTERNAL_SERVER_ERROR' }),
marker: result.marker,
}
}

return {
...result,
data: parsed.data
}
})
)
.output(schema)
}
use as:
myQuery: publicProcedure
.concat(
output(
z.strictObject({
id: z.string()
})
)
)
.query(/* */)
myQuery: publicProcedure
.concat(
output(
z.strictObject({
id: z.string()
})
)
)
.query(/* */)
myQuery's output will be typed properly as { id: string } but imho the wild use of .use() and .concat() in the wild is not good. i'd really love that we can do named procedure extensions to have a meaningful way to express these kind of plugins.

Did you find this page helpful?