danielaparker / jsoncons

A C++, header-only library for constructing JSON and JSON-like data formats, with JSON Pointer, JSON Patch, JSON Schema, JSONPath, JMESPath, CSV, MessagePack, CBOR, BSON, UBJSON
https://danielaparker.github.io/jsoncons
Other
720 stars 163 forks source link

Add a registry that can be used with JSON Schema validation #549

Open michaelmior opened 1 week ago

michaelmior commented 1 week ago

Describe the proposed feature

Many JSON Schema validators support the ability to register external schemas based on their ID so they can be resolved at validation time. The idea is that you pass in the schema and the ID and it would be saved into a local registry so that any future schemas which reference that schema by ID will discover it without needing resolution.

What other libraries (C++ or other) have this feature?

[Blaze]https://github.com/sourcemeta/blaze) is the only C++ library I am aware of.

Include a code fragment with sample data that illustrates the use of this feature

This is something that should be possible by implementing a resolver which has a method to add a schema instance.

danielaparker commented 1 week ago

I suppose we could add another parameter to make_json_schema that would allow you to provide a registry argument, say a std::map<jsoncons::uri, jsoncons::jsonschema::json_schema>, to be used for lookup while building a schema. But it would need to supply a mapped schema for, not just a schema document, but referenceable subschemas in that document as well.

Compare that with our resolver example. Here, the resolver looks like

json resolver(const jsoncons::uri& uri)
{
    std::string pathname = "./input/jsonschema/";
    pathname += std::string(uri.path());

    std::fstream is(pathname.c_str());
    if (!is)
    {
        return json::null();
    }

    return json::parse(is);        
}

To build the schema, the schema builder needs to resolve the URI http://localhost:1234/draft2020-12/name-defs.json#/$defs/orNull. But we don't make the user supply a schema specifically for that, instead, we allow the user to supply the schema document '/name-defs.json'. The schema builder than processes that schema document and makes multiple entries into an internal validator registry, including uri/validator entries for

'http://localhost:1234/draft2020-12/name-defs.json'
'http://localhost:1234/draft2020-12/name-defs.json#/$defs/orNull'
'http://localhost:1234/draft2020-12/name-defs.json#/$defs/orNull/anyOf/0'

Any subsequent need to resolve those URI's is done using the internal registry rather than the resolver.

We couldn't do something analogous with a schema registry of uri's and json_schema objects. The uri's would have to match exactly. I don't think that would be practical.

michaelmior commented 1 week ago

@danielaparker Could you clarify how the existing resolver could be used to supply just name-defs.json as in your example above? It sounds like it would then be possible to have all the subsequent URIs you listed be resolved according to that single document.

That is, can I provide the schema for http://localhost:1234/draft2020-12/name-defs.json in the resolver and then have the following all be automatically resolved?

'http://localhost:1234/draft2020-12/name-defs.json'
'http://localhost:1234/draft2020-12/name-defs.json#/$defs/orNull'
'http://localhost:1234/draft2020-12/name-defs.json#/$defs/orNull/anyOf/0'
danielaparker commented 1 week ago

That is, can I provide the schema for http://localhost:1234/draft2020-12/name-defs.json in the resolver and then have the following all be automatically resolved?

'http://localhost:1234/draft2020-12/name-defs.json'
'http://localhost:1234/draft2020-12/name-defs.json#/$defs/orNull'
'http://localhost:1234/draft2020-12/name-defs.json#/$defs/orNull/anyOf/0'

Yes.

michaelmior commented 1 week ago

Could you give an example of how that would work? It seems like this would already resolve the issue here. (Although perhaps there could end up being a somewhat nicer API for what I'm trying to achieve.)

danielaparker commented 1 week ago

Using a URIResolver to resolve references to schemas defined in external files