Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: batching with zod .optional() input #669

Merged
merged 19 commits into from Jul 19, 2021
Merged

Conversation

KATT
Copy link
Member

@KATT KATT commented Jul 18, 2021

  • JSON.stringify([undefined]) === [null]
  • this causes issues with .optional() zod schemas as it expects an object or undefined, not null
  • fixed by ugly hack that runs validator twice when it fails if the raw input was === null.
    fixed by @simonedelmann's idea

@vercel
Copy link

vercel bot commented Jul 18, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployments, click below or on the icon next to each commit.

www – ./www

🔍 Inspect: https://vercel.com/trpc/www/EuKCQujsNkMFUEYtU7NtUU38uayD
✅ Preview: https://www-git-feature-batching-edge-case.tmp.trpc.io

todomvc – ./examples/next-prisma-todomvc

🔍 Inspect: https://vercel.com/trpc/todomvc/5EDB1nCkpzGnJJHsyj6bdJdohQaz
✅ Preview: https://todomvc-git-feature-batching-edge-case.tmp.trpc.io

@KATT KATT temporarily deployed to trpcws-pr-669 July 18, 2021 23:57 Inactive
@KATT KATT requested a review from simonedelmann July 19, 2021 00:00
@KATT KATT temporarily deployed to trpcws-pr-669 July 19, 2021 00:00 Inactive
@KATT KATT changed the title fix: stringifying [undefined] gives [null] - solve by extra input pass fix: stringifying [undefined] gives [null] Jul 19, 2021
@KATT KATT marked this pull request as ready for review July 19, 2021 00:02
@KATT KATT added 🐛 bug Something isn't working @trpc/client @trpc/server labels Jul 19, 2021
@simonedelmann
Copy link
Contributor

I've just checked the PR. I am not sure if I like the hack, but it should do the job. But...

I am not sure if we should merge this. If we expect the library to always parse values correctly, we should set a transformer (SuperJSON or something similar) by default and not just handle one specific edge case. But if the library by default uses JSON.stringify and JSON.parse for encoding/decoding values and we expect our users to deal with its issues anyway (sending Dates for example), they should also be aware of this edge case and manage it on their own.

@KATT
Copy link
Member Author

KATT commented Jul 19, 2021

I am not sure if we should merge this. If we expect the library to always parse values correctly, we should set a transformer (SuperJSON or something similar) by default and not just handle one specific edge case, [...] , they should also be aware of this edge case and manage it on their own.

I understand your point of view, I just think this is a very common edge-case, especially since I want to enable batching per default (#160).

I don't wanna add transformers as default as they add a perf hit and everyone don't benefit from having them. At least not superjson, as it's slow.

I wish JSON.parse() would throw on dates/map/set as default - I might actually add a specific callback to JSON.parse() to make this happen with a note that they should add a transformer as a follow-up.

@simonedelmann
Copy link
Contributor

I understand your point of view, I just think this is a very common edge-case, especially since I want to enable batching per default (#160).

I see. So it is probably worth handling this specific case. Then I have only one more concern: Are null and undefined the only two values which are represented by "null" in JSON? So we make sure not to parse anything as undefined which actually didn't was undefined before.

I wish JSON.parse() would throw on dates/map/set as default - I might actually add a specific callback to JSON.parse() to make this happen with a note that they should add a transformer as a follow-up.

I like the idea of throwing on Dates/Maps/Sets/... by default. The only thing I would suggest then is to do a little research, what kind of problems JSON.stringify/parse has, so we are not only addressing a few but all (or at least many) of them.

@simonedelmann
Copy link
Contributor

One more question: Couldn't we solve this client-side? So if the input value is null, we send JSON.stringify(null). But if input value is not existing at all, we just send an empty string "", which is no valid JSON then but is clearly identifiable as undefined?

@KATT
Copy link
Member Author

KATT commented Jul 19, 2021

One more question: Couldn't we solve this client-side? So if the input value is null, we send JSON.stringify(null). But if input value is not existing at all, we just send an empty string "", which is no valid JSON then but is clearly identifiable as undefined?

Good idea, but it would break this code instead

export const appRouter = createRouter()
  .query('hello', {
    input: z.string().min(1).optional(),
    resolve: ({ input, ctx }) => {
      return `hello ${input ?? 'world'}`;
    },
  })

// [...]

await client.query('hello'); // will throw 

@simonedelmann
Copy link
Contributor

But why? .optional() does allow a value of undefined. So if we have no input client-side, why can't we call the parser with parser(undefined)?

@KATT KATT temporarily deployed to trpcws-pr-669 July 19, 2021 18:50 Inactive
@KATT
Copy link
Member Author

KATT commented Jul 19, 2021

@all-contributors add @simonedelmann for reviews

@allcontributors
Copy link
Contributor

@KATT

I've put up a pull request to add @simonedelmann! 🎉

@KATT KATT merged commit 87ac90b into main Jul 19, 2021
@KATT KATT deleted the feature/batching-edge-case branch July 19, 2021 20:46
@KATT KATT mentioned this pull request Aug 15, 2021
KATT added a commit that referenced this pull request Aug 20, 2021
- Reduce `TRPCError`s - `METHOD_NOT_FOUND` removed & `PATH_NOT_FOUND` renamed to `NOT_FOUND` (closes #733)
- Align input and output serialization (closes #746)
- Remove deprecated `httpErrors`-helper
- Remove support for `?input` to be an array - now assuming a `Record<number, unknown>`-style dict (changed with backward compat in #669)
- Remove support for `POST` calls being `{ input: x }` (originally from #671)
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 11, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants