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

feat(standard-validator): Add standard schema validation #887

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

muningis
Copy link

@muningis muningis commented Dec 13, 2024

Group of different Schema Validation libraries authors has agreed on a standard schema, so other libraries, don't have even to care what validation library you're using, as typings and output must match spec.

Copy link

changeset-bot bot commented Dec 13, 2024

🦋 Changeset detected

Latest commit: 58693dd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@hono/standard-validator Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@muningis muningis changed the title draft: feat(standard-validator): Add standard schema validation feat(standard-validator): Add standard schema validation Dec 13, 2024
@EdamAme-x
Copy link
Contributor

great!!

@yusukebe
Copy link
Member

Hi @muningis

This is awesome! The code below actually works!

import { Hono } from 'hono'
import { sValidator } from '@hono/standard-validator'
import { type } from 'arktype'
import * as v from 'valibot'
import { z } from 'zod'

const aSchema = type({
  agent: 'string',
})

const vSchema = v.object({
  slag: v.string(),
})

const zSchema = z.object({
  name: z.string(),
})

const app = new Hono()

app.get(
  '/:slag',
  sValidator('header', aSchema),
  sValidator('param', vSchema),
  sValidator('query', zSchema),
  (c) => {
    const headerValue = c.req.valid('header')
    const paramValue = c.req.valid('param')
    const queryValue = c.req.valid('query')
    return c.json({ headerValue, paramValue, queryValue })
  }
)

const res = await app.request('/foo?name=foo', {
  headers: {
    agent: 'foo',
  },
})

console.log(await res.json())

/**
{
  headerValue: {
    agent: "foo",
  },
  paramValue: {
    slag: "foo",
  },
  queryValue: {
    name: "foo",
  },
}
 */

I'll review this. First, can you add the CI like this: https://github.com/honojs/middleware/blob/main/.github/workflows/ci-hello.yml

@muningis
Copy link
Author

Hy! Sure, will do it later today once I'm back from work.

@yusukebe
Copy link
Member

Hey @fabian-hiller ! Can you review this?

@fabian-hiller
Copy link
Contributor

Yes, I will review it later. Make sure to add Hono to the Standard Schema ecosystem list once this is merged. 😎

Copy link
Contributor

@fabian-hiller fabian-hiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once Standard Schema is accepted by the JS community, Hono could try to implement it natively to remove the adapter altogether.

.changeset/modern-bugs-search.md Show resolved Hide resolved

```ts
import { z } from 'zod'
import { sValidator } from '@hono/standard-schema-validator'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a mismatch in package names. Here @hono/standard-schema-validator is used but in the package.json it is named @hono/standard-validator.

packages/standard-validator/package.json Show resolved Hide resolved
},
"homepage": "https://github.com/honojs/middleware",
"peerDependencies": {
"@standard-schema/spec": "1.0.0-beta.4",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the latest RC version of the spec.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I would probably add it as a direct dependency and not as under peerDependencies and devDependencies.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yusukebe WDYT? For example, we have same with other validators, such as zod or valibot.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, when using the Hono Valibot adapter, you already have Valibot installed, otherwise the adapter makes no sense. With Standard Schema this is different, as any library that supports the spec is compatible. Users will never install Standard Schema themselves. Note that Standard Schema contains only types and no runtime code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have heard that dev dependencies may not be installed when a package is installed. So adding it as a dependency might be safer. But feel free to investigate and report back.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@muningis

I think you should add @standard-schema/spec as a direct dependency, as @fabian-hiller pointed out. It is used in packages/standard-validator/src/index.ts, so it's natural to do it.

packages/standard-validator/package.json Show resolved Hide resolved
/**
* For headers, all keys are lower-cased, so we have to transform them.
*/
if (target === 'header' && isStandardSchemaValidator(schema) && schema['~standard'].types) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

schema['~standard'].types is always undefined at runtime because we just store type information here. This implementation should probably be changed or removed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I guess tests has issues then if they passed. Will have to adjust.
And it will have to be changed, as we need to re-write keys of a schema/shape, so that all keys are lower-cased.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not possible. Standard Schema does not contain an AST-like structure. Why is it necessary to rewrite the keys? Shouldn't users take care of this when writing the schema?

return c.json({ data: validatorValue, error: result.issues, success: false }, 400)
}

return result.value as StandardSchemaV1.InferOutput<Schema>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is type casting necessary here? result.value should already be typed after we know result.issues is undefined.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, yeah. (Same is required by zod and valibot validators).

It comes down to some type issues coming from hono/validator (haven't had chance to dive in yet).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants