f# - How do I define a Json Schema containing definitions, in code -
i attempting replicate following json schema
example, defining schema in code using newtonsoft.json.schema
:
{ "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "address": { "type": "object", "properties": { "street_address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" } }, "required": ["street_address", "city", "state"] } }, "type": "object", "properties": { "billing_address": { "$ref": "#/definitions/address" }, "shipping_address": { "$ref": "#/definitions/address" } }
this close i've got far. (example in f# might in c#.)
code:
open newtonsoft.json.schema open newtonsoft.json.linq let makeschema = let addressschema = jschema() addressschema.properties.add("street_address", jschema(type = nullable(jschematype.string))) addressschema.properties.add("city", jschema(type = nullable(jschematype.string))) addressschema.properties.add("state", jschema(type = nullable(jschematype.string))) addressschema.required.add "street_address" addressschema.required.add "city" addressschema.required.add "state" let schema = jschema() schema.properties.add("billing_address", addressschema) schema.properties.add("shipping_address", addressschema) schema
output:
{ "properties": { "billing_address": { "properties": { "street_address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" } }, "required": [ "street_address", "city", "state" ] }, "shipping_address": { "$ref": "#/properties/billing_address" } } }
as can see, 1 of 2 addresses defined using reference schema, , address schema in "properties" rather "definitions". what's trick defining schema in "definitions" , referencing elsewhere?
hackfest! :-)
according source code, json.net schema doesn't write definitions
property, end of story. it's hopeless... almost.
it use definitions
property in place, however. namely - when generating schema type. during process, creates jobject
, pushes schemas it, , adds object jschema.extensiondata
under definitions
key. , when referencing schema place, schema writer respect definitions
object, if present, making whole thing work together.
so, armed knowledge, can hack our way it:
let makeschema = let addressschema = jschema() ... let definitions = jobject() :> jtoken definitions.["address"] <- addressschema |> jschema.op_implicit let schema = jschema() schema.extensiondata.["definitions"] <- definitions schema.properties.add("billing_address", addressschema) schema.properties.add("shipping_address", addressschema) schema
and voila! resulting schema has definitions
object, sacred texts tell should:
{ "definitions": { "address": { "properties": { "street_address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" } }, "required": [ "street_address", "city", "state" ] } }, "properties": { "billing_address": { "$ref": "#/definitions/address" }, "shipping_address": { "$ref": "#/definitions/address" } } }
a few notes:
- the
definitions
name not special json.net's point of view. if change lineschema.extensiondata.["definitions"]
different,schema.extensiondata.["xyz"]
, still work, references pointing"#/xyz/address"
. this whole mechanism, obviously, hackapparently not, according james netwon-king. key insight seemsjsonschemawriter
able lookup previous mentions of schemas , use references them in other places. allows 1 shove schemas wherever 1 likes , expect them referenced.- that
op_implicit
call in there necessary.jschema
not subtype ofjtoken
, can't jamdefinitions.["address"]
that, have convertjtoken
first. fortunately, there implicit cast operator defined that. unfortunately, it's not straightforward, there seems magic going on. happens transparently in c# (because, know, there not enough confusion is), in f# have call explicitly.
Comments
Post a Comment