pboettch / json-schema-validator

JSON schema validator for JSON for Modern C++
Other
466 stars 134 forks source link

📚️ What about "readOnly" ? (draft 7 section 10.3) #212

Closed opsocket closed 1 year ago

opsocket commented 1 year ago

Hi there 👋

As of now, the validator does not honor section 10.3 from the specification JSON Schema Validation: A Vocabulary for Structural Validation of JSON.

I am interested in this excerpt specifically:

If "readOnly" has a value of boolean true, it indicates that the value of the instance is managed exclusively by the owning authority, and attempts by an application to modify the value of this property are expected to be ignored or rejected by that owning authority.

It is clearly stated that attempts by an application to change the value of this property must be ignored or rejected.

I was expecting one of these two options for validation:

  1. Ignoring properties for which the schema defines a "readOnly" key with a value of true
  2. Throwing an exception informing the user that the value for this key is read-only
pboettch commented 1 year ago

I think the key to understand how read-only works is the phrase "change the value of this property". When does a value change? Clearly not during validation.

It seems to me that this is not validator's work. The validator is not the "owning authority". It is your application.

But maybe the validator can be used as an instance or frontend for your application to apply this functionality.

opsocket commented 1 year ago

This library encapsulates everything needed to honor this section easily. The user does not have any clue about all the objects that composes the specified schema tree behind the scene, if there was access i might agree with you. The user would have to rewrite some parts of this library to identify the readOnly nodes, which is not really ideal.

opsocket commented 1 year ago

It certainly doesn't cover everything from Schema Annotations, but it does the trick for now 🍻

pboettch commented 1 year ago

As I wrote in the PR: the validator could extract and provide a list of json-paths which you could use in your applicaiton to handle the read and write-Only fields. What do you think?

opsocket commented 1 year ago

As written in #213, I think that

it's an attractive idea too but it adds an unnecessary burden to the user from my point of view

Oh yea and instead of generating an error, we need to find a way to make this "json list" (of pointers or paths, whatever) accessible to the user and I don't see a clean way to do that.

Anyway, this would involve similar changes from #213

pboettch commented 1 year ago

Coming back to your original idea: could you create a (pseudo)-code snippet of how you would like to use this feature as a user with the validator? Here's my vision:

This schema

{
  "properties": {
    "foo": { "type": "int", "readOnly": true},
    "bar": { "type": "int", "writeOnly": true},
    "baz": { "type": "int"}
  }
}

Initial instance:

{"foo": 42, "baz": 101}

Usage:

validator.validate(instance); // OK
std::cout << instance["foo"] << "\n"; // OK
std::cout << instance["bar"] << "\n";  // throws WriteOnlyException
std::cout << instance["baz"] << "\n";
instance["foo"] = 43;  // throws ReadOnlyException
instance["bar"] = 1;  // OK
instance["baz"] = 12;  // OK

How would you implement this using the validator? I don't see any way do it with the validator except for using a list of paths/pointers as helper and a wrapper to which evaluates this list and throws when we access the properties the wrong way.

opsocket commented 1 year ago

Your usage example implies subclassing of / overriding methods from nlohmann::json because of the requirement to throw write and read exceptions upon access

This is a costly implementation and the wrong way to go in my opinion.

I would implement this by tagging / annotating any type_schema objects created at the validation stage, with some booleans to assert key existance (as in #213 with readonly).

An alternative to raising an error for these annotated instances would be to aggregate json pointers to these instances into read / write vectors and let the user manage the logic for handling these annotations but as a user this is painful.

Note that writeOnly has another meaning that is beyond the scope of #213

I'd go this way:

auto p = validator.validate(instance); // OK, returns hierarchical defaults patch
instance = instance.patch(p); // OK, instance is now validated and `readOnly` keys were present in the patch to override values from the instance that cannot be written

Note that the code there is forcing the user to patch its instance to get the true valid one, this is prone to user errors

pboettch commented 1 year ago

IIUC: your idea is to say that read-only values can only be set by the default-value of a schema and an initial value is not allowed to be present in an instance which is read-only?

opsocket commented 1 year ago

By definition, a read-only value cannot be written to so, yes, these can only be set by using the default keyword.

Allowing an "initial write" for these would prevent them from qualifying as "true" read-only properties of the schema.

We might be able to find answers regarding initial values in the following sentence:

If "readOnly" has a value of boolean true, it indicates that the value of the instance is managed exclusively by the owning authority

My understanding of "managed exclusively" is that initial values are not allowed for a readOnly property as it would break exclusivity

pboettch commented 1 year ago

OK, and there we are again, you say the owning authority is the validator and I don't think so. Proof me wrong with the help of other examples from other (JSON schema validation) projects, otherwise I won't change my mind.

opsocket commented 1 year ago

Well, I'm done. I'd better spend my time rewriting this library. Get another round of "Why are you wrong?" anytime. Go and ask around "Who is the owning authority?" if you feel like it.

In a last effort to make you understand, I let you read this and deduce what you want

https://json-schema.org/draft/2020-12/json-schema-validation.html#section-9.4

If "writeOnly" has a value of boolean true, it indicates that the value is never present when the instance is retrieved from the owning authority. It can be present when sent to the owning authority to update or create the document (or the resource it represents), but it will not be included in any updated or newly created version of the instance.