8000 fix: use ajv for schema ref resolving by ivan-tymoshenko · Pull Request #462 · fastify/fast-json-stringify · GitHub
[go: up one dir, main page]

Skip to content
8000

fix: use ajv for schema ref resolving #462

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

Merged

Conversation

ivan-tymoshenko
Copy link
Member
@ivan-tymoshenko ivan-tymoshenko commented Jun 13, 2022

Reopen #454
Fix #452 #417 #350

The idea behind this solution is to use ajv's addSchema and getSchema methods to resolve json schema references. To do this, as the serializer is built, it keeps track of and updates a reference to the current location. The reference consists of schema id + json pointer. When it needs to validate subschema (if/else, oneof, anyof), it uses the reference.

There are two tests that use an incorrect format of json schema id/ref. They will not work after this fix.

  1. It's an external schema that uses a schema key (base URI) that starts with #. As it is considered a schema key if it can start with #. # should be used only as a local anchor inside the schema.

    test('ref in definition with exact match', (t) => {

  2. It uses a reference combined with the other two references.

    test('ref in root external multiple times', (t) => {

And as we have a reference for the current location in the schema we can use it as a comment inside anonymous functions instead of building a custom version of json pointer (locationPath).

@ivan-tymoshenko ivan-tymoshenko force-pushed the use-ajv-for-schema-ref-resolving branch from e08cc63 to ac7fd4d Compare June 13, 2022 10:29
@ivan-tymoshenko
Copy link
Member Author

Before merging, it is needed to resolve fastify's failed tests. #454 (comment)

@mcollina
Copy link
Member

Could you send a PR to Fastify to update this? Feel free to use a git-dependency to verify.

@ivan-tymoshenko
Copy link
Member Author

@mcollina @climba03003 Am I right that Fastify allows adding global (external) schemas for serialization only if they have $id property?
https://github.com/fastify/fastify/blob/2af47f06bf94fe1538ca84c5e350f90cfa803066/lib/schemas.js#L26

And if the schema does have $id property it always equals the schema's key?
https://github.com/fastify/fastify/blob/2af47f06bf94fe1538ca84c5e350f90cfa803066/lib/schemas.js#L35

If so, can we consider that all external schemas received from Fastify have the $id property and it always equals key?

@mcollina
Copy link
Member

I think the right person to ask is @Eomm.

@climba03003
Copy link
Member
climba03003 commented Jun 14, 2022

Yes, it would be better if you ask Eomm.
He spited the schema controller from fastify to fast-json-stringify-compiler and ajv-compiler.

Since, the function you pointing to is shared between ajv and fjs. I think your assumption is true.
But I would expect it may change in future. Since ajv also allow id field as the schema id.

@ivan-tymoshenko
Copy link
Member Author

But I would expect it may change in future. Since ajv also allow id field as the schema id.

@climba03003 If so, what behavior would you expect for this feature?

Copy link
Member
@Eomm Eomm left a comment

Choose a reason for hiding this comment

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

I think this PR simply a lot the code and fixes some tests that were wrong.

We must be aware that we are relying more on AJV to store&get the schema. For this reason, I think we may hit a performance drop at startup because ajv clones all the schemas added via ajv.addSchema.

Am I right that Fastify allows adding global (external) schemas for serialization only if they have $id property?

Yes, it is a good assumption, but I saw the JSON key fallback that I think is reasonable.

Before merging a draft PR against fastify should be linked to be sure all cases are covered. I expect some fixes on the fastify's tests 😄

@mcollina
Copy link
Member

I'm a bit confused. Should we ship this as minor or major?

@ivan-tymoshenko
Copy link
Member Author

This will break some cases that don't follow the json schema draft 7 standard. IMHO these cases shouldn't be popular, but I don't have any statistics so IDK. This PR changes two wrong tests behavior. All Fastify tests will pass after merging this fastify/fast-json-stringify-compiler#14. Although @climba03003 makes sense here #464 (comment), that some people can have some wrong use cases that are not covered with our tests.

On the other hand, it fixes so many basic cases, so I don't really want to wait a year for Fastify@5.

Maybe it makes sense to release it as @climba03003 suggested #464 (comment), and if it turns out that many wrong cases do not work, revert the changes or patch some popular wrong cases until the next major release.

@Eomm wdyt?

@Eomm
Copy link
Member
Eomm commented Jun 18, 2022

I think this PR deserves to be shipped with fastify@4, but I think it needs some more checks about perf impact.

Could @ivan-tymoshenko share the results? I will try the bench script too.

@ivan-tymoshenko
Copy link
Member Author

Unfortunately, it has a significant performance drop on cold start. I will think if something can be done about it.

@ivan-tymoshenko ivan-tymoshenko marked this pull request as draft June 19, 2022 14:09
@ivan-tymoshenko
Copy link
Member Author

I found the problem. I disabled ajv schema validation.

Cold start benchmark results:

Main branch

Снимок экрана 2022-06-19 в 18 23 05

Feature branch

Снимок экрана 2022-06-19 в 18 40 46

Benchmark: https://gist.github.com/ivan-tymoshenko/18abb40f5b4bdf27fb520eeb10b735f1

@ivan-tymoshenko ivan-tymoshenko marked this pull request as ready for review June 19, 2022 15:43
@ivan-tymoshenko ivan-tymoshenko marked this pull request as draft June 19, 2022 16:03
@Eomm
Copy link
Member
Eomm commented Jun 19, 2022

from my test, this PR does not impact this repo's benchmark script.

Maybe it worth adding a bench test with some $refs. WDYT?

@ivan-tymoshenko
Copy link
Member Author
ivan-tymoshenko commented Jun 19, 2022

@Eomm try this one. https://gist.github.com/ivan-tymoshenko/18abb40f5b4bdf27fb520eeb10b735f1

  1. Do you have external schemas on your test cases?
  2. Did you test cold start?

@ivan-tymoshenko
Copy link
Member Author
ivan-tymoshenko commented Jun 19, 2022

from my test, this PR does not impact this repo's benchmark script.

This PR shouldn't affect runtime. All changes are about stringify func compilation.

@ivan-tymoshenko ivan-tymoshenko marked this pull request as ready for review June 19, 2022 16:58
@Eomm
Copy link
Member
Eomm commented Jun 20, 2022

I run this: https://github.com/fastify/fast-json-stringify/tree/master/benchmark

Your test results:

➜  fast-json-stringify git:(master)
FJS cold start x 16,301 ops/sec ±0.39% (594 runs sampled)

➜  fast-json-stringify git:(PULL_462)
FJS cold start x 14,241 ops/sec ±0.39% (594 runs sampled)

Looking if we could set something else to reduce this little drop

Copy link
Member
@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

lgtm, I'm shipping this right now.
We can sort out the performance later on.

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