shale icon indicating copy to clipboard operation
shale copied to clipboard

Allow customization of JSON schema $defs key and $ref

Open mdesantis opened this issue 11 months ago • 4 comments

Suppose you have the following code:

class Person; end

class PersonMapper < Shale::Mapper
  model Person
end

require 'shale/schema'

puts Shale::Schema.to_json(
  PersonMapper,
  pretty: true
)

You get

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/Person",
  "$defs": {
    "Person": {
      "type": "object",
      "properties": {}
    }
  }
}

But, what if you want a $defs key and $ref calculated differently from the current logic? This is the cleanest way I've figured out so far:

def schema_with_custom_defs_key_and_ref(mapper, defs_key:)
  schema = Shale::Schema::JSONGenerator.new.as_schema(mapper)
  old_defs_key = mapper.model.name
  old_ref = schema['$ref']
  new_defs_key = defs_key
  new_ref = "#/defs/#{new_defs_key}"

  schema['$ref'] = new_ref
  schema['$defs'][new_defs_key] = schema['$defs'].delete(old_defs_key)

  schema
end

puts JSON.pretty_generate(schema_with_custom_defs_key_and_ref(PersonMapper, defs_key: 'User'))

Which gives

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$ref": "#/defs/User",
  "$defs": {
    "User": {
      "type": "object",
      "properties": {}
    }
  }
}

But it's quite cumbersome. What about something like

class PersonMapper < Shale::Mapper
  model Person

  json do
    defs_key 'User'
  end
end

Another option I guess would be to pass defs_key to as_schema, e.g.:

Shale::Schema::JSONGenerator.new.as_schema(PersonMapper, defs_key: 'User')

But I'm new to JSON schemas, I don't know which one makes more sense

mdesantis avatar Mar 01 '24 19:03 mdesantis

What you're doing is probably the best way to change refs at the moment. I'm curious, what is the use case for doing that?

kgiszczak avatar Mar 02 '24 13:03 kgiszczak

I'm curious, what is the use case for doing that?

Basically these are my mappers:

module ShaleMappers
  class Model < Shale::Mapper
    model ::Model
    ...

Which would make the $defs key to be ShaleMappers_Model but I'd like to have just Model. Also, in case of a model namespace, I'm not enthusiast of having _ as separator, I'd like to use something else (I was even thinking of /, but I'm new to JSON schemas so I'm unsure it makes sense), so yeah stuff like this

UPDATE Actually, I was wrong about the ShaleMappers_Model point, I've just realized I miswrote the model forgetting the ::, that's why ShaleMappers_ was included in the $defs key. But the argument about the _ still remains.

mdesantis avatar Mar 02 '24 17:03 mdesantis

(btw thanks for this library, I love that it doesn't have any open issues nor pull requests so much that opening one made me sad :joy: )

mdesantis avatar Mar 02 '24 17:03 mdesantis

Thanks. Like I said, for now I would stick to what you're doing currently. I might implement it in the future, but for now I don't have much free time.

kgiszczak avatar Mar 04 '24 15:03 kgiszczak