vpjm
FormData TRPCClientError
solution :
// TRPC PROVIDER file
export class FormDataTransformer implements DataTransformer {
serialize(object: any) {
if (!(object instanceof FormData)) {
throw new Error("Expected FormData");
}
return object;
}
deserialize(object: any) {
return object as JSON;
}
}
function TRPCProviders(props: Readonly<{ children: React.ReactNode }>) {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
splitLink({
condition: (op) => !isNonJsonSerializable(op.input) && op.type !== "subscription" && !op.context["stream"],
true: httpBatchLink({url: getUrl(),transformer }),
false: splitLink({
condition: (op) => isNonJsonSerializable(op.input) && op.type !== "subscription" && !op.context["stream"],
true: httpLink({
url: getUrl(),transformer: new FormDataTransformer(),
}),
false: splitLink({
condition: (op) => op.type === "subscription" && !op.context["stream"],
true: unstable_httpSubscriptionLink({
url: getUrl(),transformer
}),
false: unstable_httpBatchStreamLink({
url: getUrl(),transformer
}),
}),
}),
}),
],
}),
);
return (
<QueryClientProvider client={getQueryClient()}>
<trpc.Provider client={trpcClient} queryClient={queryClient}>
{props.children}
</trpc.Provider>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
// TRPC PROVIDER file
export class FormDataTransformer implements DataTransformer {
serialize(object: any) {
if (!(object instanceof FormData)) {
throw new Error("Expected FormData");
}
return object;
}
deserialize(object: any) {
return object as JSON;
}
}
function TRPCProviders(props: Readonly<{ children: React.ReactNode }>) {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
splitLink({
condition: (op) => !isNonJsonSerializable(op.input) && op.type !== "subscription" && !op.context["stream"],
true: httpBatchLink({url: getUrl(),transformer }),
false: splitLink({
condition: (op) => isNonJsonSerializable(op.input) && op.type !== "subscription" && !op.context["stream"],
true: httpLink({
url: getUrl(),transformer: new FormDataTransformer(),
}),
false: splitLink({
condition: (op) => op.type === "subscription" && !op.context["stream"],
true: unstable_httpSubscriptionLink({
url: getUrl(),transformer
}),
false: unstable_httpBatchStreamLink({
url: getUrl(),transformer
}),
}),
}),
}),
],
}),
);
return (
<QueryClientProvider client={getQueryClient()}>
<trpc.Provider client={trpcClient} queryClient={queryClient}>
{props.children}
</trpc.Provider>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
14 replies
FormData TRPCClientError
I try to simplify again but : look like the same error
Uncaught (in promise) TRPCClientError: [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"name"
],
"message": "Required"
},
{
"code": "custom",
"message": "Input not instance of File",
"fatal": true,
"path": [
"image"
]
}
]
Uncaught (in promise) TRPCClientError: [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"name"
],
"message": "Required"
},
{
"code": "custom",
"message": "Input not instance of File",
"fatal": true,
"path": [
"image"
]
}
]
14 replies
FormData TRPCClientError
As Nick Lucas advised me, I went back to the basics
//QueryClient
export const createQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 30 * 1000,
},
}})
//PROVIDER
function TRPCProviders(props: Readonly<{ children: React.ReactNode }>) {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
splitLink({
condition: (op) => op.type === 'subscription',
true: unstable_httpSubscriptionLink({
url: getUrl(),
/**
* @see https://trpc.io/docs/v11/data-transformers
*/
transformer,
}),
false: unstable_httpBatchStreamLink({
url: getUrl(),
/**
* @see https://trpc.io/docs/v11/data-transformers
*/
transformer,
}),
}),
],
}),
);
return (
<QueryClientProvider client={getQueryClient()}>
<trpc.Provider client={trpcClient} queryClient={queryClient}>
{props.children}
</trpc.Provider>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
//QueryClient
export const createQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 30 * 1000,
},
}})
//PROVIDER
function TRPCProviders(props: Readonly<{ children: React.ReactNode }>) {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
splitLink({
condition: (op) => op.type === 'subscription',
true: unstable_httpSubscriptionLink({
url: getUrl(),
/**
* @see https://trpc.io/docs/v11/data-transformers
*/
transformer,
}),
false: unstable_httpBatchStreamLink({
url: getUrl(),
/**
* @see https://trpc.io/docs/v11/data-transformers
*/
transformer,
}),
}),
],
}),
);
return (
<QueryClientProvider client={getQueryClient()}>
<trpc.Provider client={trpcClient} queryClient={queryClient}>
{props.children}
</trpc.Provider>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
14 replies
FormData TRPCClientError
// ENDPOINT TRPC
const uploadFileSchema = zfd.formData({
name: zfd.text(),
image: zfd.file(),
});
export const appRouter = createTRPCRouter({
//...
myEndpoint: publicProcedure.input(uploadFileSchema).mutation(async (opts) => {
console.log(opts.input);
})
})
const uploadFileSchema = zfd.formData({
name: zfd.text(),
image: zfd.file(),
});
export const appRouter = createTRPCRouter({
//...
myEndpoint: publicProcedure.input(uploadFileSchema).mutation(async (opts) => {
console.log(opts.input);
})
})
14 replies
FormData TRPCClientError
export function Upload() {
const mutation = trpc.myEndpoint.create.useMutation({
onError(err) {
alert('Error from server: ' + err.message);
},
});
const schema = zfd.formData({
name: zfd.text(),
image: zfd.file(),
});
const form = useZodFormData({
schema,
});
const [noJs, setNoJs] = useState(false);
return (
<>
<FormProvider {...form}>
<form
method="post"
action={`/api/trpc/${mutation.trpc.path}`}
encType="multipart/form-data"
onSubmit={(_event) => {
if (noJs) {
return;
}
void form.handleSubmit(async (values, event) => {
await mutation.mutateAsync(new FormData(event?.target));
})(_event);
}}
style={{ display: 'flex', flexDirection: 'column', gap: 10 }}
ref={form.formRef}
>
<fieldset>
<div style={{}}>
<label htmlFor="name">Enter your name</label>
<input {...form.register('name')} />
{form.formState.errors.name && (
<div>{form.formState.errors.name.message}</div>
)}
</div>
<div>
<label>Required file, only images</label>
<input type="file" {...form.register('image')} />
{form.formState.errors.image && (
<div>{form.formState.errors.image.message}</div>
)}
</div>
<div>
<button type="submit" disabled={mutation.status === 'pending'}>
submit
</button>
</div>
</fieldset>
</form>
</FormProvider>
</>
);
}
export function Upload() {
const mutation = trpc.myEndpoint.create.useMutation({
onError(err) {
alert('Error from server: ' + err.message);
},
});
const schema = zfd.formData({
name: zfd.text(),
image: zfd.file(),
});
const form = useZodFormData({
schema,
});
const [noJs, setNoJs] = useState(false);
return (
<>
<FormProvider {...form}>
<form
method="post"
action={`/api/trpc/${mutation.trpc.path}`}
encType="multipart/form-data"
onSubmit={(_event) => {
if (noJs) {
return;
}
void form.handleSubmit(async (values, event) => {
await mutation.mutateAsync(new FormData(event?.target));
})(_event);
}}
style={{ display: 'flex', flexDirection: 'column', gap: 10 }}
ref={form.formRef}
>
<fieldset>
<div style={{}}>
<label htmlFor="name">Enter your name</label>
<input {...form.register('name')} />
{form.formState.errors.name && (
<div>{form.formState.errors.name.message}</div>
)}
</div>
<div>
<label>Required file, only images</label>
<input type="file" {...form.register('image')} />
{form.formState.errors.image && (
<div>{form.formState.errors.image.message}</div>
)}
</div>
<div>
<button type="submit" disabled={mutation.status === 'pending'}>
submit
</button>
</div>
</fieldset>
</form>
</FormProvider>
</>
);
}
14 replies
FormData TRPCClientError
Now I have the same endpoint and frontend as https://github.com/trpc/examples-next-formdata, but it still doesn't work.
14 replies
FormData TRPCClientError
//CLIENT FORM
//TRPC PROVIDER
//ENDPOINT TRPC
const url = `/test/upload/${uuidv4()}`
const formData = new FormData();
formData.append('file', data.image);
formData.append('metadata', JSON.stringify({
filename,
type:"IMAGE",
extension,
img_width: width,
img_height: height,
..._.pick(file,["size","name"]),
video_length:null,
mimeType:"IMAGE_JPEG"
}));
formData.append('url', url);
await createPost.mutateAsync(formData)
const url = `/test/upload/${uuidv4()}`
const formData = new FormData();
formData.append('file', data.image);
formData.append('metadata', JSON.stringify({
filename,
type:"IMAGE",
extension,
img_width: width,
img_height: height,
..._.pick(file,["size","name"]),
video_length:null,
mimeType:"IMAGE_JPEG"
}));
formData.append('url', url);
await createPost.mutateAsync(formData)
function TRPCProviders(props: Readonly<{ children: React.ReactNode }>) {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
splitLink({
condition: (op) => op.type === 'subscription',
true: unstable_httpSubscriptionLink({
url: getUrl(),
/**
* @see https://trpc.io/docs/v11/data-transformers
*/
transformer,
}),
false: unstable_httpBatchStreamLink({
url: getUrl(),
/**
* @see https://trpc.io/docs/v11/data-transformers
*/
transformer,
}),
})
],
}),
);
function TRPCProviders(props: Readonly<{ children: React.ReactNode }>) {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
splitLink({
condition: (op) => op.type === 'subscription',
true: unstable_httpSubscriptionLink({
url: getUrl(),
/**
* @see https://trpc.io/docs/v11/data-transformers
*/
transformer,
}),
false: unstable_httpBatchStreamLink({
url: getUrl(),
/**
* @see https://trpc.io/docs/v11/data-transformers
*/
transformer,
}),
})
],
}),
);
const uploadFileSchema = zfd.formData({
url: zfd.text(),
file: zfd.file(z.instanceof(File)),
metadata: zfd.json(z.any()),
});
export const appRouter = createTRPCRouter({
uploadFile: publicProcedure.input(uploadFileSchema).mutation(async (opts) => {
console.log(opts.input);
})})
const uploadFileSchema = zfd.formData({
url: zfd.text(),
file: zfd.file(z.instanceof(File)),
metadata: zfd.json(z.any()),
});
export const appRouter = createTRPCRouter({
uploadFile: publicProcedure.input(uploadFileSchema).mutation(async (opts) => {
console.log(opts.input);
})})
14 replies
FormData TRPCClientError
/**
* Creates context for an incoming request
* @see https://trpc.io/docs/v11/context
*/
export const createTRPCContext = async (opts: FetchCreateContextFnOptions) => {
const session = await auth();
return {
session,
};
};
export type Context = Awaited<ReturnType<typeof createTRPCContext>>;
/**
* Creates context for an incoming request
* @see https://trpc.io/docs/v11/context
*/
export const createTRPCContext = async (opts: FetchCreateContextFnOptions) => {
const session = await auth();
return {
session,
};
};
export type Context = Awaited<ReturnType<typeof createTRPCContext>>;
const handler = (req: NextRequest) =>
fetchRequestHandler({
router: appRouter,
req,
endpoint: '/api/trpc',
/**
* @see https://trpc.io/docs/v11/context
*/
createContext: createTRPCContext,
/**
* @see https://trpc.io/docs/v11/error-handling
*/
onError: process.env.NODE_ENV === "development" ? ({ path, error }) => {
console.error(
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`
);
}
: undefined,
});
export { handler as GET, handler as POST };
const handler = (req: NextRequest) =>
fetchRequestHandler({
router: appRouter,
req,
endpoint: '/api/trpc',
/**
* @see https://trpc.io/docs/v11/context
*/
createContext: createTRPCContext,
/**
* @see https://trpc.io/docs/v11/error-handling
*/
onError: process.env.NODE_ENV === "development" ? ({ path, error }) => {
console.error(
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`
);
}
: undefined,
});
export { handler as GET, handler as POST };
export const createQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 30 * 1000,
},
dehydrate: {
serializeData: transformer.serialize,
shouldDehydrateQuery: (query) =>
defaultShouldDehydrateQuery(query) ||
query.state.status === "pending",
},
hydrate: {
deserializeData: transformer.deserialize,
},
},
});
export const createQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 30 * 1000,
},
dehydrate: {
serializeData: transformer.serialize,
shouldDehydrateQuery: (query) =>
defaultShouldDehydrateQuery(query) ||
query.state.status === "pending",
},
hydrate: {
deserializeData: transformer.deserialize,
},
},
});
14 replies