-
-
Notifications
You must be signed in to change notification settings - Fork 97
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
Proposal: Support custom resolvers for external references #246
Comments
Hi @tamasfe
Not at the moment, but I was thinking of implementing it one day (my goal was to be as extendable as the Python
I am delighted to see this proposal! Thank you so much for bringing this up :) I am going to look deeper into details next week, but currently, I feel positive about this :) Here are my thoughts on the details: It might be better to reuse the existing builder pattern and set resolver there: let compiled = JSONSchema::options()
.with_resolver(resolver)
.compile(&schema) So, the default resolver will be chosen if nothing is provided to the builder. On the So, it might be Let me know what do you think :) |
I'm glad you're up for it! :) I would very much prefer bringing resolution forward to the compilation phase, in a lot of cases it is done only once, while validations can easily be part of hot loops. (this is also how Ajv works) Circular references are indeed a blocker for this, I will look into the library a bit deeper and figure out ways to handle them cleanly. My argument against making the With the API I'm proposing, the compilation/validation would look like this: let mut resolver = MyResolver::default();
let schema_validator = JSONSchema::compile_async_with(&schema, &mut resolver).await?;
let another_schema_validator = JSONSchema::compile_async_with(&another_schema, &mut resolver).await?;
'hot: loop {
// No async here, should be as fast as possible.
schema_validator.validate(&some_input)?;
another_schema_validator.validate(&another_input)?;
} |
Indeed, it will be very beneficial! In this case, I hope we can get rid of
But it still carried by
My concern is that it introduces the second way for configuring Though, at the moment, for me, it is hard to compare those approaches, probably some more implementation details will be helpful. On the |
I'm not so sure that you can move all reference resolving to the compilation phase. In particular the data access vocabulary requires looking up a value somewhere else in the document currently being validated, this value can contain references so that means you would need to be able to do resolution at runtime. Obviously this is something that would have performance implications and is not something you would want to allow in general, so maybe it would be worth distinguishing in the type system in some way. |
I'm just concerned about the boilerplate, no breaking API change is involved with any changes I have in mind. Introducing generic types for
After looking more into it, I believe what you suggest would be better, we'd have to make
That's unfortunate, then we have to box the resolver anyway, even worse require it to be Clone, so that each validator can have its own instance of it. We can still make everything generic over it in the compilation phase though.
I don't think that it's necessary, as I believe it wouldn't be different from a validator (currently isn't), if no resolution is needed, a validator is simply not made for it. |
Another note on this is that because we pull in some sort of clock somewhere, we can't validate without a reference to a "now" function. In WASM we may not want time to be defined for determinism -- I was able to work around this by making a no_mangle |
* feat: resolver * chore: rustfmt * chore: even more rustfmt * chore: relax anyhow version requirement * chore: restore url dependency requirement * fix(resolver): jsonschema/src/resolver.rs typo Co-authored-by: Dmitry Dygalo <Stranger6667@users.noreply.github.com> * fix(resolver): python binding * feat(resolver): include original ref string, docs * feat(resolver): reqwest feature compile error * chore(resolver): changelog * fix(*): clippy * fix(resolver): doctest example * feat(resolver): reqwest feature compile error * chore(resolver): changelog * fix(*): clippy * fix(resolver): doctest example
Hi, I'm planning to use this library in my project, which is mostly used a constrained WASM environment.
This means that the filesystem, and http requests might not be directly available.
Is supporting a custom external resolver possible?
I propose the following:
Turn
Resolver
into a trait that could be used to resolve schemas in an unknown environment.I'm thinking of something like this:
Then allow compilations with a custom resolver while providing a default one:
Additionally an async version could be supported in a similar way which could help with resolution of many references. This would also be needed to support reqwest in WASM contexts.
There are several questions to resolve (such as custom error types and schema caching, and probably more).
Are you open to the idea?
The text was updated successfully, but these errors were encountered: