I am creating an API using Zod and TRPC, and I can't guarantee that all of the clients will upgrade immediately upon deploy (e.g. long opened tabs).
I would like to deprecate fields out of the TRCP input or output schema without forcing an immediate client refresh; and I didn't spot an approach to doing this in the docs.
If I have missed any easier approach, please let me know :)
Proposal
A deprecated method which removes the key from the input, or output, types based on the setting (naming just a first-thought, not a suggestion).
input:
optional in validation
is not in the input type
is in the output type
output:
same as before in validation (optional or required)
is in the input type
is not in the output type
Why not just temporarily use optional
For input types, it will not prevent consumers from continuing to attempt to supply this data. A two step deprecation allows all consumer code to be updated (and type checked) before updating the server code.
For output types, it ensures that no consumers are still expecting this field before the server stops sending it entirely
In both situations, deprecating for a situation-appropriate amount of time helps to avoid API mismatch.
Examples
export const appRouter = t.router({
hello: publicProcedure
.input(
z.object({
// consumers of this API route will not see `name` in the input types
// but it is still available here to be responded to for old consumers
name: z.string().deprecated('input'),
}),
)
.query((opts) => {
const name = opts.input.name;
if (name) { /* do the old version */ }
else { /* do the new version */ }
return {
greeting: "Hello",
};
}),
});
export const appRouter = t.router({
// this method is being deprecated, so new consumers will see `{}` as the output type
// it will still work for older consumers, allowing time for all clients to update to the latest build
// this specific situation may be better managed at a TRPC level as well
hello: publicProcedure
.input(
z.object({
name: z.string().deprecated('input'),
}),
)
.output(
z.object({
greeting: z.string().deprecated('output'),
}),
)
.query((opts) => {
const name = opts.input.name;
return {
greeting: "Hello",
};
}),
});
Use case
I am creating an API using Zod and TRPC, and I can't guarantee that all of the clients will upgrade immediately upon deploy (e.g. long opened tabs).
I would like to deprecate fields out of the TRCP input or output schema without forcing an immediate client refresh; and I didn't spot an approach to doing this in the docs.
If I have missed any easier approach, please let me know :)
Proposal
A
deprecated
method which removes the key from the input, or output, types based on the setting (naming just a first-thought, not a suggestion).input
:output
:Why not just temporarily use
optional
input
types, it will not prevent consumers from continuing to attempt to supply this data. A two step deprecation allows all consumer code to be updated (and type checked) before updating the server code.output
types, it ensures that no consumers are still expecting this field before the server stops sending it entirelyIn both situations, deprecating for a situation-appropriate amount of time helps to avoid API mismatch.
Examples