qwik icon indicating copy to clipboard operation
qwik copied to clipboard

feat: add Valibot support with `valibot$` to qwik-city

Open brandonpittman opened this issue 2 years ago β€’ 56 comments

Overview

Adds Valibot support with a valibot$ function similarly to how Zod is supported by zod$.

Fixes #4924

What is it?

  • [x] Feature / enhancement
  • [ ] Bug
  • [ ] Docs / tests / types / typos

Description

Requires:

  • valibot

Use cases and why

So you can use Valibot to validate your actions

Checklist:

  • [x] My code follows the developer guidelines of this project
  • [x] I have performed a self-review of my own code
  • [x] I have made corresponding changes to the documentation
  • [ ] Added new tests to cover the fix / functionality

brandonpittman avatar Aug 24 '23 09:08 brandonpittman

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

Deploy Preview for qwik-insights canceled.

Name Link
Latest commit bfb1d8a25fc15ca41ed58a0a3c7c2025bc0293db
Latest deploy log https://app.netlify.com/sites/qwik-insights/deploys/651de4314b616a0008a4368f

netlify[bot] avatar Aug 24 '23 09:08 netlify[bot]

Thanks for your nice PR, can you add the documentation for this please?

gioboa avatar Aug 24 '23 09:08 gioboa

Thanks for your nice PR, can you add the documentation for this please?

Sure. Not done, yet. Will update docs tomorrow! Just wanted to share what I had so far.

@fabian-hiller Is there a way with Valibot to check if a value is an ObjectSchema at runtime?

brandonpittman avatar Aug 24 '23 11:08 brandonpittman

@brandonpittman yes, this should work via the .schema key: https://github.com/fabian-hiller/valibot/blob/v0.13.1/library/src/schemas/object/object.ts#L65

And via .async you can find out if it needs to be validated async: https://github.com/fabian-hiller/valibot/blob/v0.13.1/library/src/schemas/object/object.ts#L75

fabian-hiller avatar Aug 24 '23 11:08 fabian-hiller

Note that you must also include BaseSchemaAsync and ObjectShapeAsync to support async validation.

fabian-hiller avatar Aug 24 '23 11:08 fabian-hiller

Note that you must also include BaseSchemaAsync and ObjectShapeAsync to support async validation.

@fabian-hiller

It's not clear if we need async support. I've updated my PR with working code that satisfies TypeScript. I've removed any async types though. Can you take a look, please?

brandonpittman avatar Aug 25 '23 03:08 brandonpittman

It's not clear if we need async support.

Since the validation is done in an async function, we could enable async validation with safeParseAsync, BaseSchemaAsync and ObjectShapeAsync. This would allow, for example, to do network requests as part of the validation. If someone uses only sync validation, this is not a disadvantage. async is compatible with sync, but sync is not compatible with async.

fabian-hiller avatar Aug 25 '23 08:08 fabian-hiller

If you want to add async support, you need to replace safeParse with safePareseAsync and also add BaseSchemaAsync and ObjectShapeAsync to the types.

fabian-hiller avatar Aug 25 '23 08:08 fabian-hiller

If you want to add async support, you need to replace safeParse with safePareseAsync and also add BaseSchemaAsync and ObjectShapeAsync to the types.

Okay. Will update it. Thanks.

brandonpittman avatar Aug 25 '23 11:08 brandonpittman

You must not remove BaseSchema and ObjectShape from the types. Otherwise the sync validation will not be accepted.

fabian-hiller avatar Aug 25 '23 12:08 fabian-hiller

You must not remove BaseSchema and ObjectShape from the types. Otherwise the sync validation will not be accepted.

@fabian-hiller

Should I use BaseSchema instead of ObjectSchema<ObjectShape>? When I tried BaseSchema the .schema === "object' check encountered a type error.

Do I need to do something like obj.async ? safeParseAsync(obj, data) : safeParse(obj, data) or can I just give safeParseAsync a synchronous schema?

brandonpittman avatar Aug 25 '23 13:08 brandonpittman

Thanks for working on this! ❀️

mhevery avatar Aug 25 '23 16:08 mhevery

Should I use BaseSchema instead of ObjectSchema<ObjectShape>? When I tried BaseSchema the .schema === "object' check encountered a type error.

I think I would write BaseSchema | BaseSchemaAsync | ObjectShape | ObjectShapeAsync. If we recognize that an object with typeof obj._parse === "function" is passed, it is a scheme that can be passed directly in safeParseAsync. Otherwise the object must be passed into objectAsync before we call safeParseAsync.

Do I need to do something like obj.async ? safeParseAsync(obj, data) : safeParse(obj, data) or can I just give safeParseAsync a synchronous schema?

This is not required. safeParseAsync can also handle BaseSchema.

fabian-hiller avatar Aug 25 '23 17:08 fabian-hiller

Thank you very much @brandonpittman and @fabian-hiller πŸ™

One thought from my side regarding exporting both libs now from the qwik-city pkg is, if we should think about flag the zod$ and z exports as deprecated? it shouldn't be our long term goal to keep both within the framework imo. end users would still be able to additionally add zod$ if they want to keep it. @mhevery would like to pass that to you and the team πŸ˜„

zanettin avatar Aug 27 '23 20:08 zanettin

CleanShot 2023-08-30 at 10 18 03@2x

@mhevery

I updated the validation heading structure because I added separate Valibot sections. Is this okay?

brandonpittman avatar Aug 30 '23 01:08 brandonpittman

No problems with the runtime code, but there's a lot of Zod-specific types mixed into the routeAction-adjacent types (starting here: https://github.com/BuilderIO/qwik/blob/d27177d1e4749805492d23164f9e655142f24601/packages/qwik-city/runtime/src/types.ts#L810-L813C2).

Going to need to update them to play nicely with Valibot types.

brandonpittman avatar Aug 30 '23 07:08 brandonpittman

Thank you @brandonpittman for your efforts! πŸ’™

fabian-hiller avatar Aug 30 '23 10:08 fabian-hiller

Thank you @brandonpittman for your efforts! πŸ’™

@fabian-hiller I think the last thing should be adjusting the action value type. After removing the any, it’s not correctly type hinting the error key when failed is true. I still need to figure that out.

brandonpittman avatar Aug 30 '23 10:08 brandonpittman

Can you highlight what you mean? Then I can have a look at it.

fabian-hiller avatar Aug 30 '23 10:08 fabian-hiller

@fabian-hiller

starts here: https://github.com/BuilderIO/qwik/blob/3d4715e4a4b76eed3db3163f7850bee8d7dfc089/packages/qwik-city/runtime/src/types.ts#L827-L851

continues through to here: https://github.com/BuilderIO/qwik/blob/3d4715e4a4b76eed3db3163f7850bee8d7dfc089/packages/qwik-city/runtime/src/types.ts#L419-L608

The types for the routeAction$ success value seem fine, but when there's an error, I had trouble getting the error values to correctly type hint. TypeScript doesn't think nested will exist when action.value.failed === true.

https://github.com/BuilderIO/qwik/blob/7412c64fcf85999fc347d64316c340611f1e1ea4/packages/docs/src/routes/demo/valibot/simple/index.tsx#L34

I also haven't been able to get correct types for returned values in the template. Getting TS errors that say the value isn't valid JSXβ€”but it displays just fine in practice.

https://github.com/BuilderIO/qwik/blob/7412c64fcf85999fc347d64316c340611f1e1ea4/packages/docs/src/routes/demo/valibot/simple/index.tsx#L54

brandonpittman avatar Aug 30 '23 11:08 brandonpittman

Thanks for the info. I will have a closer look next week.

fabian-hiller avatar Aug 30 '23 14:08 fabian-hiller

Thanks for the info. I will have a closer look next week.

Hopefully I can figure it out before then. πŸ˜†

brandonpittman avatar Aug 30 '23 14:08 brandonpittman

Ok. Sorry. I'm moving this weekend. Otherwise I would have looked at it right away.

fabian-hiller avatar Aug 30 '23 14:08 fabian-hiller

Ok. Sorry. I'm moving this weekend. Otherwise I would have looked at it right away.

@fabian-hiller Sorry, I hope that didn't sound like I was rushing you. I just meant I really want to solve the problem. I'm very grateful for all the help you've given me so far. πŸ™‡πŸ»

brandonpittman avatar Aug 30 '23 14:08 brandonpittman

I will try to review the changes in the next few days.

fabian-hiller avatar Sep 07 '23 16:09 fabian-hiller

Thank you @brandonpittman. I will check your changes tomorrow.

fabian-hiller avatar Sep 11 '23 02:09 fabian-hiller

@fabian-hiller

Is there any way to get type hints out of flatten()? FlatErrors isn't generic, so I can't see a way to pass a schema type along to get type hints from the return value of flatten().

brandonpittman avatar Sep 11 '23 05:09 brandonpittman

Currently this is not possible. Do you know if this works with Zod? I think it will be difficult to make it completely type-safe.

fabian-hiller avatar Sep 11 '23 15:09 fabian-hiller

Currently this is not possible. Do you know if this works with Zod? I think it will be difficult to make it completely type-safe.

@fabian-hiller

Zod has a couple helpers for inferring flattened error types.

https://github.com/colinhacks/zod/blob/f59be093ec21430d9f32bbcb628d7e39116adf34/src/ZodError.ts#L7-L16

brandonpittman avatar Sep 12 '23 00:09 brandonpittman