GithubHelp home page GithubHelp logo

jsonschema's People

Contributors

alecthomas avatar arvidfm avatar bunyk avatar candiduslynx avatar dcermak avatar deepjyoti30 avatar elgris avatar ewen-lbh avatar gmlewis avatar gutjuri avatar hotdawg avatar inteon avatar jaskirat8 avatar jawn-smith avatar kindermoumoute avatar mathewth avatar mitar avatar muff1nman avatar negz avatar nigelis avatar patrick246 avatar paulcacheux avatar s00500 avatar samlown avatar sguiheux avatar shabinesh avatar tooolbox avatar twpayne avatar webdestroya avatar zamicol avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

jsonschema's Issues

I'm unable to escape 'comma' in regex

score.go

type Score struct {
	Percent string `json:"percent,omitempty" jsonschema:"omitempty,pattern=^(0|[1-9][0-9]?)(([.])([0-9]{1,5}))?$,description=Percentage to achieve( 0>= anyscore < 100 example: 0, 10, 90, 99.9999)"`
	....
	....
	....
}

result jsonschema

{
 "$schema": "http://json-schema.org/draft-04/schema#",
 "properties": {
  "percent": {
   "pattern": "^(0|[1-9][0-9]?)(.[0-9]{1",
   "type": "string",
   "description": "Percentage of SLO to achieve(100 or 0 or between 1 and 99)"
  },
 
 },
 "additionalProperties": false,
 "type": "object"
}

this can be resolved like ^(0|[1-9][0-9]?)(([.])([0-9]|[0-9]{2}|[0-9]{3}|[0-9]{4}|[0-9]{5}))?$ .. but need a better solution ... TIA

Pattern keyword do not appear when = character is in regex

As the title suggests, adding an = character in the regex seems to break the reflector. Using jsonschema_extras instead as a workaround is not ideal as it doesn't parse escaped commas.

Example:
Using this struct

type S struct{
	Normal string `jsonschema:"pattern=$\\,=^"`
	Extras string `jsonschema_extras:"pattern=$\\,=^"`
	NoEquals string `jsonschema:"pattern=$\\,^"`
}

Generates this schema

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$ref": "#/$defs/S",
    "$defs": {
        "S": {
            "properties": {
                "Normal": {
                    "type": "string"
                },
                "Extras": {
                    "type": "string",
                    "": "^",
                    "pattern": "$\\"
                },
                "NoEquals": {
                    "type": "string",
                    "pattern": "$,^"
                }
            },
            "additionalProperties": false,
            "type": "object",
            "required": [
                "Normal",
                "Extras",
                "NoEquals"
            ]
        }
    }
}

No support for recursive structures

The project I am working on includes structures that are a subset of json-schema itself. That is, a struct that can include an array or map of references to its own type.

With the following structs:

type Flat struct {
String string
Array []string
}

type Recursive struct {
String string
Array []*Recursive
}

Flat encodes fine, but Recursive results in a stack overflow.

A more complicated example of a struct that won't encode is the jsonschema.Schema struct itself, since it includes the following field

AllOf []*Schema `json:"allOf,omitempty"` // section 10.2.1.1

There doesn't seem to be a way to capture the fact that types may need references to IDs before the schemmas are fully generted.

Override jsonschema property

Hi, I would like to know how to override/remove some jsonschema property.

In the example below, the MAC attribute is a slice of bytes and is represented as {"type":"string","contentEncoding":"base64"} in the generated schema. However, in my case I made a custom marshaller so as to turn this slice into a string. So I would like to remove the contentEncoding attribute in the schema.

I have tried to change its value but it is not reflected in the schema.

package main

import (
	"encoding/json"
	"fmt"
	"net"

	"github.com/invopop/jsonschema"
)

type NIC struct {
	Name string           `json:"name,omitempty"`
	MAC  net.HardwareAddr `json:"mac,omitempty" jsonschema:"contentEncoding=quoted-printable"`
}

func (nic *NIC) MarshalJSON() ([]byte, error) {
	type Alias NIC

	mac := ""
	if nic.MAC != nil {
		mac = nic.MAC.String()
	}

	return json.Marshal(&struct {
		MAC string `json:"mac,omitempty"`
		*Alias
	}{
		MAC:   mac,
		Alias: (*Alias)(nic),
	})
}

func main() {
	schema := jsonschema.Reflect(&NIC{})
	data, _ := schema.MarshalJSON()
	fmt.Println(string(data))
}
# output
{"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/NIC","$defs":{"HardwareAddr":{"type":"string","contentEncoding":"base64"},"NIC":{"properties":{"name":{"type":"string"},"mac":{"$ref":"#/$defs/HardwareAddr"}},"additionalProperties":false,"type":"object"}}}

Lacking documentation

Is there a documentation of the tags beside me having to go through the source code and guess what's doing what?

schema.Extras

Question. If I would like to Unmarshal my JSON schema bytes which contain custom attributes, should the Extras field contain those attributes?

I tried that, but it looks empty now.

Tag "minimum=0" should not omit

The omitempty in below always remove tag jsonschema:minimum=0.

Minimum           int                 `json:"minimum,omitempty"` 

What if i want add a tag minimum=0 for any number property in schema.MarshalJSON output, the Minimum should chang to:

Minimum           *int                 `json:"minimum,omitempty"` 

Schema with empty name for anonymous types

schema := jsonschema.Reflect((*struct {
	T []struct {
		Key   string      `json:"key"`
		Value interface{} `json:"value"`
	} `json:"table"`
})(nil))

produces (see on the Go playground):

{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/",
  "$defs": {
    "": {
      "properties": {
        "table": {
          "$ref": "#/$defs/"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "table"
      ]
    }
  }
}

The schema is recursive while the original Go type isn't. It looks like there is a problem in handling of anonymous types. Even more, when there is multiple anonymous types the result is completely corrupted.

For anonymous types I expect an inline schema, not a schema defined via a reference under #/$defs.

Expected schema:

{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "properties": {
    "table": {
      "items": {
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string"
          },
          "value": {
          }
        },
        "required": [
          "name",
          "value"
        ],
        "type": "object"
      },
      "type": "array",
    }
  },
  "required": [
    "table"
  ],
  "type": "object"
}

Add automated changelog

Hello,

This library is really awesome but it's sometimes difficult to identify what changed between two versions.
It's seems that all changes done to this library are done via pullrequest so I think the current project would
highly benefit from https://github.com/release-drafter/release-drafter

Release drafter automatically release changelog based on pullrequest titles.

[IDEA] Expose more interface to add specific part of json schema

Hello everyone !

I just came across a situation, where I wanted to add an anyof attribute to my json-schema, but didn't want to overwrite all subschemas with a func (MyStruct) JSONSchema() and then lose all the reflection on my struct tags.

So I thought we could expose more interface{} to add specific part in the final json-schema, what do you think ?

I just did a simple test on my fork here: #49

I would be happy to discuss it with you !

Feature Request: Enable Default Value Setting in Schemas via Unaltered Struct Field Names

Feature Request

Problem
When generating a schema, it would be beneficial to have the capability to set default values using an instance of the struct that is being converted into a schema.

Currently, this is challenging because the name specified in the struct tags may not correspond to the actual name of the struct field in the code, which makes it difficult to match the fields using their names.

Proposed Solution
To resolve this, we could include the original name of the struct field—unmodified by struct tags—in the schema. This would preserve the ability to match the fields based on their original names in the code, facilitating the setting of default values.

Alternatives Considered
An alternative method I have considered involves replacing the field name of the instantiated object with the name specified in the tag and using that for matching. However, this approach does not fully address the problem, as the name from the tag might be altered by a function like KeyNamer.

Field should only be marked required if set in JSON Schema

I've been trying to figure out why all of my struct fields are being marked as required until I found this in your code.

In effect, if I don't specify the JSON omitempty tag, it will mark all struct fields as required.

IMHO, the required condition should be set via your tags and not by omitempty. The omitempty tag prevents the JSON from outputting that field if it is not defined, but that doesn't necessarily mean that it is required or not. This also means that we need to mark every struct field as either omitempty or required.

How to set $id for slices?

Hey everyone,

I tried to add an ID to a slice based schema type today but wasn't able to find out how to achieve this.
Minimal required steps are:

	r := new(jsonschema.Reflector)

	schema := r.Reflect(&[]struct{}{})
	json, _ := schema.MarshalJSON()
	println(string(json))

the output is:

{
"$schema":"https://json-schema.org/draft/2020-12/schema",
"items":{"properties":{},"additionalProperties":false,"type":"object"},
"type":"array"
}

Which options do I have to add an $id field here?

Thanks in advance 🙇

Require field if other is set (dependentRequired)

I'm trying to mark a struct field as required, but only if another field is set.

It looks like this can be done with the dependentRequired or dependentSchemas keywords in the JSON Schema syntax.
I found these on this Stack Overflow question.

Can this be added to your library, or do you have a better way to do what I am attempting to accomplish?

Field comments include unmeaningful newlines

Comments on types correctly have single newlines stripped from them, but comments on fields do not. This is because of the behavior described in the documentation for ExtractGoComments:

When parsing type comments, we use the go/doc's Synopsis method to extract the first phrase only. Field comments, which tend to be much shorter, will include everything.

Synopsis is also the mechanism by which unmeaningful newlines are stripped, so we also lose this behavior for fields.

Related to (but not solved by) #67.

from map (bson.M) instead of struct?

this library seems to work fine with structs, but what about maps like bson.M{}?

For example, this code:

package main

import (
	"encoding/json"
	"fmt"
	"github.com/invopop/jsonschema"
	"go.mongodb.org/mongo-driver/bson"
)

// Define your struct here. This should mirror your JSON data.

type MyData struct {
	Name    string `json:"name"`
	Age     int    `json:"age"`
	Address string `json:"address,omitempty"`
}

func main() {
	// Generate a JSON schema for your struct

	{

		schema := jsonschema.Reflect(&MyData{})

		// Marshal the schema into JSON
		schemaJSON, err := json.MarshalIndent(schema, "", "  ")
		if err != nil {
			panic(err)
		}

		// Print the JSON schema
		fmt.Println(string(schemaJSON))
	}

	{
		var MyData = bson.M{
			"this_is_string": "value",
			"this_is_int":    5,
			"this_is_struct": &MyData{
				Name:    "<name?",
				Age:     0,
				Address: "<address>",
			},
		}
		schema := jsonschema.Reflect(&MyData)

		// Marshal the schema into JSON
		schemaJSON, err := json.MarshalIndent(schema, "", "  ")
		if err != nil {
			panic(err)
		}

		// Print the JSON schema
		fmt.Println(string(schemaJSON))
	}
}

yields this output:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/MyData",
  "$defs": {
    "MyData": {
      "properties": {
        "name": {
          "type": "string"
        },
        "age": {
          "type": "integer"
        },
        "address": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "name",
        "age"
      ]
    }
  }
}
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://go.mongodb.org/mongo-driver/bson/primitive/m",
  "$ref": "#/$defs/M",
  "$defs": {
    "M": {
      "type": "object"
    }
  }
}

this schema def is not really correct (or useful at least):

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://go.mongodb.org/mongo-driver/bson/primitive/m",
  "$ref": "#/$defs/M",
  "$defs": {
    "M": {
      "type": "object"
    }
  }
}

Custom schema attribute which is a JSON array.

I use jsonschema_extras to add my own schema attributes. But unfortunately, it does not work with JSON array values (don't confuse them with multiple values)

An example:

Some interface{} `json:"some,omitempty" jsonschema_extras:"requiredWhen=[1,2,3]"`

Returns me

..."some":{"requiredWhen":"[1"}},"additionalProperties":false....

I guess the problem is with a comma separator.
Should I try implementing JSONSchema? Would it be possible with it?

Many thanks in advance!

How about `[]struct { Key string; Value *jsonschema.Schema }` instead of orderedmap?

I'm not knocking orderedmap but it doesn't enable inline definitions, which can be tedious if you want/need to create custom Schemas as it breaks the flow of the definition.

Using

type Obj []struct {
	Field string
	Value *jsonschema.Schema
}

enables this sort of API:

func (CreateTenantRequest) JSONSchema() *jsonschema.Schema {
	return &jsonschema.Schema{
		Type: "object",
		Properties: jsonschema.Obj{
			{"name", &jsonschema.Schema{}},
		},
	}
}

instead of:

func (CreateTenantRequest) JSONSchema() *jsonschema.Schema {
	p := orderedmap.New()
	p.Set("name", &jsonschema.Schema{
		Type: "string",
	})
	return &jsonschema.Schema{
		Type: "object",
		Properties: p,
	}
}

Marshaling/Unmarshaling the JSON is incredibly straightforward with tidwall/sjson & tidwall/gjson:

https://go.dev/play/p/OxCa0Vyv6l4 (I used strings as the value to keep things simple / concise for demo purposes). Error checking and such was omitted as well.

Also, thanks for the package.

Allow .JSONSchema() to return the result of Reflect

Sometimes I find that when I have a custom MarshalJSON and UnmarshalJSON I am basically building a different structure and then returning json.Marshal(newType), so that my code looks like:

type SomeType struct {...}

type otherType struct {...}

func (s SomeType) MarshalJSON() ([]byte, error) {
    var o *otherType = convertSomeTypeToOtherType(s)
    return json.Marshal(o)
}

(a real-world example I'm dealing with right now is a map[string]string that needs to be handed to a system that forbids additional properties, so MarshalJSON converts it to a []struct{key:string, value:string} and marshals that instead).

It would be great if I could also write:

func (s SomeType) JSONSchema() *jsonschema.Schema {
	return jsonschema.Reflect(otherType{})
}

The returned schema from Reflect has .Version set and its own internal .Definitions, though, and these don't get merged to the top, so I end up with an invalid final schema, with something like

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/SomeType",
  "$defs": {
    "SomeType": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$ref": "#/$defs/otherType",
      "$defs": {
        "otherType": {...}
}}}}

I can get around this by defining

func (s SomeType) JSONSchema() *jsonschema.Schema {
	reflector := jsonschema.Reflector{
		DoNotReference:            true,
	}
	schema := reflector.Reflect(otherType{})
	schema.Version = ""
	return schema
}

but this seems clunky and forces me to fully expand otherType without references.

A) Is there a better way to do this?
B) If not, is there any reason why reflectCustomSchema couldn't check for definitions and a version on the returned schema, and extract and merge them into its own definitions if applicable?

got nil pointer when using costom JSONSchema func

func (Coustom) JSONSchema() *jsonschema.Schema { return &jsonschema.Schema{ Type:"string", } }

I just add this func to my coustom struct, and got a nil pointer from here:

github.com/invopop/jsonschema.(*Reflector).reflectCustomSchema(0x7f6855c136f8?, 0x7f687f7d8108?, {0xbe1478, 0xad3980})
/home/XXX/go/pkg/mod/github.com/invopop/[email protected]/reflect.go:423 +0xb0
github.com/invopop/jsonschema.(*Reflector).reflectTypeToSchema(0xc00021fa58, 0xc00021f960?, {0xbe1478, 0xad3980})
/home/XXX/go/pkg/mod/github.com/invopop/[email protected]/reflect.go:348 +0x89
github.com/invopop/jsonschema.(*Reflector).reflectTypeToSchemaWithID(0xc00021fa58, 0xbe1478?, {0xbe1478, 0xad3980})
/home/XXX/go/pkg/mod/github.com/invopop/[email protected]/reflect.go:324 +0x2c
github.com/invopop/jsonschema.(*Reflector).ReflectFromType(0xc00021fa58, {0xbe1478, 0xad3980})
/home/XXX/go/pkg/mod/github.com/invopop/[email protected]/reflect.go:244 +0xf3
github.com/invopop/jsonschema.(*Reflector).Reflect(0xb0?, {0xad3980?, 0xc0000c3340?})
/home/XXX/go/pkg/mod/github.com/invopop/[email protected]/reflect.go:230 +0x4a

I tried func (*Coustom) JSONSchema() *jsonschema.Schema ,but still got the same error.

Did I make a mistake somewhere?

Issue with generics

if you use generics in some type for which schema is generated, in reference generated name will contain path of the generic argument. Which is an issue as in json schema references / is used to identify the reference. I fixed it with this snippet:

r := new(jsonschema.Reflector)
r.Namer = func(t reflect.Type) string {
  return strings.ReplaceAll(t.Name(), "/", "__")
}

Tho this is something that should probably be done by default.

Kebab-case $id fields break Python jschon parser

Structs are currently rendered as kebab-case in the "$id" field.
For example, TestUser becomes:

"$id": "https://github.com/invopop/jsonschema/test-user"

When another field attempts to reference this struct, the Python3.10 "jschon" package resports this error:

jschon.exc.CatalogError: A source is not available for "https://github.com/invopop/jsonschema/TestUser"

but if the "$id" line is changed from test-user to TestUser, then the "jschon" package parses the file successfully.

I will work on a PR for this issue.

How to build API?

How should I build API schema when I have http methods, paths and json schema for requests and responses?

Right now I am thinking about map[HTTP_METHOD:HTTP_PATH]{Request: {}, Response{}} but it does not feel right.

Also, is there a way to generate openapi from this, or some kind of web-ish documentation for technically less literate folk?

if we have same struct name, then we will got the same `$ref`

Assuming we have two different packages HTTP and TCP, and they all have a Config structure.

package http

type Config struct {
	URL    string `json:"url" jsonschema:"required,format=uri"`
	Method string `json:"method" jsonschema:"required"`
}
package tcp

type Config struct {
	Host string `json:"host" jsonschema:"required,format=hostname"`
	Port int    `json:"port" jsonschema:"required,minimum=1,maximum=65535"`
}

then, we have a struct involving these two packages

package server

type AllConfig struct {
	TCP  tcp.Config  `json:"tcp" jsonschema:"omitempty"`
	HTTP http.Config `json:"http" jsonschema:"omitempty"`
}

then we will have the same $ref = #/$defs/Config for http and tcp in JSON Schema, but actually, the http.Config is quite different with tcp.Config, this causes the incorrect the JSON schema file.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/invopop/jsonschema/test/all-config",
  "$ref": "#/$defs/AllConfig",
  "$defs": {
    "AllConfig": {
      "properties": {
        "tcp": {
          "$ref": "#/$defs/Config"
        },
        "http": {
          "$ref": "#/$defs/Config"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": ["tcp", "http"]
    },
    "Config": {
      "properties": {
        "host": {
          "type": "string",
          "format": "hostname"
        },
        "port": {
          "type": "integer",
          "maximum": 65535,
          "minimum": 1
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": ["host", "port"]
    }
  }
}

So, is there a way we can define the $ref name to make sure they are using different $defs.

Feature request: Add ability to preserve comment newlines in AddGoComments

It would be nice to be able to preserve the newlines and full text in a "description" string (as "\n") so that other tools can take advantage of the formatting already performed in the original source.

I'm thinking that this option should be added as an optional flag at the end of the AddGoComments method.

I'll try to put together a PR.

Maybe add support for a JSONSchema interface to types?

This is a fantastic library - thank you!

I'm very new to JSON schemas but am wondering if we can use Go interfaces to give more fine-grained control over JSON schemas to the underlying types represented, similar to how Go's MarshalJSON and UnmarshalJSON work. This would be an alternative mechanism to the existing jsonschema.Reflector.Mapper function.

For example, consider the following type:

package mypackage

type CoinFlip string

const (
    CoinFlipHeads CoinFlip = "heads"
    CoinFlipTails CoinFlip = "tails"
)

Let's give it a JSONSchema method:

func (CoinFlip) JSONSchema() *jsonschema.Schema {
    return &jsonschema.Schema{
        Type: "string",
        Enum: []interface{}{
            "heads",
            "tails",
        },
    }
}

and define an interface in the jsonschema package:

package jsonschema

type JSONSchema interface {
    JSONSchema() *jsonschema.Schema
}

Now, when generating the JSON schema for a field, we can first check if the field's type implements in the JSONSchema interface, and, if so, call its JSONSchema() method directly. If the field's type does not implement the JSONSchema interface then we can continue with the existing behavior.

Such an approach would effectively allows types to define their own schemas.

Does this make sense? I would be happy to help implement such a feature.

Extend JSON Schema method

Jotting down this idea... there are a lot of requests to be able to support more advanced definitions which start getting really complex inside Go tags. The current JSONSchema() method helps support these cases, but has the tradeoff that you need to define the whole model.

A possible alternative could be to support an JSONSchemaExt(base *jsonschema.Schema) method that will generate the base schema for the Type as much as it can, then allow the type to override and add any additional fields, e.g.:

func (User) JSONSchemaExt(base *jsonschema.Schema) {
  base.AnyOf = &jsonschema.Schema{.....}
}

Postprocessing of schemas based on field information

Is there any way to postprocess the generated schema for a type to add additional information given the corresponding StructField object? E.g. to implement custom tags. There's jsonschema_extras, but it's relatively limited in that it only really works with string or string array values. Reflector.Mapper only passes the Type, not the StructField, and in any case it's somewhat tricky to use Mapper to tell jsonschema to do its own thing and only modify the result (if you just call ReflectFromType recursively, the definitions map which is passed down the call chain in jsonschema doesn't get populated, which leads to weird behaviour elsewhere, plus you have to be careful so you don't accidentally recurse infinitely).

Omit empty overrides required

I have noticed that if I put omit empty, it overrides the jsonschema:"required" tag. I feel that this should be the opposite.

Example

type Test struct {
  Name  string  `json:"name,omitempty" jsonschema:"required"`
}

This will not be marked as required

How to add items close to a array in the oneOf schema?

This is example of desired schema:

// desired schema ("items": ... are close to "type: "array")
{
    "$schema": "http://json-schema.org/draft/2020-12/schema",
    "$ref": "#/$defs/Foo",
    "$defs": {
        "Foo": {
            "properties": {
                "foos": {
                    "oneOf": [
                        {
                            "items": {
                                "$ref": "#/$defs/Foo"
                            },
                            "type": "array"
                        },
                        {
                            "type": "null"
                        }
                    ]
                }
            },
            "additionalProperties": false,
            "type": "object"
        }
    }
}

Bellow is actually a generated schema:

// generated by
// Foos []Foo `json:"foos,omitempty" jsonschema:"oneof_type=array;null,type=array"`
{
    "$schema": "http://json-schema.org/draft/2020-12/schema",
    "$ref": "#/$defs/Foo",
    "$defs": {
        "Foo": {
            "properties": {
                "foos": {
                    "oneOf": [
                        {
                            "type": "array"
                        },
                        {
                            "type": "null"
                        }
                    ],
                    "items": {
                        "$ref": "#/$defs/Foo"
                    },
                    "type": "array"
                }
            },
            "additionalProperties": false,
            "type": "object"
        }
    }
}

Is it possible to get desired schema using invopop/jsonschema tags (annotations)?

Thanks

(This is only question. Feel free to close this issue after answering this question)

Add option for "format" of array items

Currently we have the ability to use "format" for non-array types. I would like to extend this functionality to arrays as well.

Example:

type Repo struct {
	Branch string   `yaml:"branch" json:"Branch,omitempty"`
	URLs   []string `yaml:"urls"   json:"URLs"    jsonschema:"type=array,format=uri"`
	Names  []string `yaml:"names"  json:"Names"`
}

var jsonReflector jsonschema.Reflector

schema := jsonReflector.Reflect(&Repo{})

generates the following schema:

{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/Repo",
  "$defs": {
    "Repo": {
      "properties": {
        "Branch": {
          "type": "string"
        },
        "URLs": {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "Names": {
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "URLs",
        "Names"
      ]
    }
  }
}

Note that the "items" section for URLs does not include "format": "uri" in the items section, and therefore invalid URIs will not be caught when validating against this schema.

Ignore fields

Is there a way to tell the tool to ignore some fields when creating the schema?
For example: jsonschema:"ignore"

Duplicated entries in "required" array

I have a struct that defines base model:

type BaseParameters struct {
	Hotel string `json:"hotel" jsonschema:"title=Hotel ID,description=Hotel ID"`
}

And a struct that defines client model, which is a subset of base model:

type Hotel string

var Hotels []interface{} = []interface{}{"15603"}

type Parameters struct {
	BaseParameters

	Hotel Hotel `json:"hotel"`
}

func (Hotel) JSONSchema() *jsonschema.Schema {
	return &jsonschema.Schema{
		Type: "string",
		Title: "Hotel ID",
		Description: "Hotel ID",
		Enum: Hotels,
	}
}

Json schema is:

{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/Parameters",
  "$defs": {
    "Hotel": {
      "type": "string",
      "enum": ["15603"],
      "title": "Hotel ID",
      "description": "Hotel ID"
    },
    "Parameters": {
      "properties": {
        "hotel": {
          "$ref": "#/$defs/Hotel"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "hotel",
        "hotel"
      ]
    }
  }
}

Is it by design that required contains two entries of hotel?

JSON inline ignored

When using json:",inline" the generated schema still shows a separate nested object rather than inlining it.

See https://go.dev/play/p/zbh54GJfLsO.

type Params struct {
	Name     string
	Settings *struct {
		Foo string
		Bar string
	} `yaml:",inline" json:",inline"`
}

Is rendered like this

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/Params",
  "$defs": {
    "Params": {
      "properties": {
        "Name": {
          "type": "string"
        },
        "Settings": {
          "properties": {
            "Foo": {
              "type": "string"
            },
            "Bar": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "type": "object",
          "required": [
            "Foo",
            "Bar"
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "Name",
        "Settings"
      ]
    }
  }
}

Instead of what I would expect i.e.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/Params",
  "$defs": {
    "Params": {
      "properties": {
        "Name": {
          "type": "string"
        },
        "Foo": {
          "type": "string"
        },
        "Bar": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "Name",
        "Foo",
        "Bar"
      ]
    }
  }
}

support "type": ["object", "null"]

I need to set "type": ["object", "null"] in my json schema, but haven't found a way to do this. Is there a way?

For now I use Reflect and then set .Type = "[object, null]" and then when the schema is done I do a replace all.. it works, but is a little hacky

Is `anyof_required` supported?

I saw from the examples in README that oneof_required is supported however there was no mention of anyOf. Looked through the source code and found that there's just one place in the code where anyOf is defined but for oneof_required there were a few lines that was parsing the oneof_required into the parent. Code for that can be found here

My question is whether or not anyof_required is supported in the same way that oneof_required is supported. I tried generating the schema with anyof_required and it didn't generate any anyOf array however anyOf is a valid part of JSON schema so it should be supported?

AddGoComments can not use "windows" paths with backslash

This is not a big issue but I noticed that on windows when constructing paths using path.join or related the comments
did not load. But if I replaced all the backslashes (normal microsoft) with slashes (the rest of the world) it works.

Slashes works
reflector.AddGoComments("github.com/lavoqualis/messages.go", "./sources" )
but backslash
reflector.AddGoComments("github.com/lavoqualis/messages.go", ".\\sources" )
doesn't.

Custom Slice type doesn't support default values in struct tags

Hey, I've been trying to generate a schema for a custom slice type which is a field in a struct, but the default values aren't computed

type MyString string
type MyStrings []MyString

type MyObject struct {
        strs MyStrings `json:"my_strings" jsonschema:"description=This is my description,default=some,default=other"`
}

The MyStrings definition is correct, with a schema of type array, and items of type string. In the struct schema, there is the property my_strings, which points to the MyStrings ref and with the CORRECT description. But there are no default values. I evaluated this by marshaling the resulting schema.

As soon as I use []string instead of MyStrings, the default values show up

I may try to fix it on my spare time, but does anyone have any clue on what might be going on?

Replace reflector configuration with Options struct and helper methods

The current Reflector struct should be replaced with a set of option functions provided at run time. This a more idiomatic approach and results in an immutable configuration for each reflection invocation.

The objective is to end up with something like this:

s := jsonschema.Reflect(TestUser{}, jsonschema.WithBaseSchemaID("https://example.com/schemas"))

Shared options can be assigned to an array:

opts = []jsonschema.Option{
  jsonschema.WithBaseSchemaID("https://example.com/schemas"),
  jsonschema.AllowAdditionalProperties(),
}
s := jsonschema.Reflect(TestUser{}, opts...)

Nullable not recognized by jsonschema2md

I am trying to use the generated schema of this library together with jsonschema2md to generate markdown documentation but I am running into an issue with nullable fields.

A field with the tag nullable, as seen below

FailedAt   *time.Time `json:"failed_at" jsonschema:"nullable,title=FailedAt,description=Optional timestamp from when this check result item failed"`

produces:

        "failed_at": {
          "oneOf": [
            {
              "type": "string",
              "format": "date-time",
              "title": "FailedAt",
              "description": "Optional timestamp from when this check result item failed"
            },
            {
              "type": "null"
            }
          ]

Which is documented by jsonschema2md as

`failed_at`

*   is required

*   Type: merged type ([Details](result-defs-result-properties-failed_at.md))

*   cannot be null

*   defined in: [Result](result-defs-result-properties-failed_at.md)

#### failed\_at Type

merged type ([Details](result-defs-result-properties-failed_at.md))

one (and only one) of

*   [FailedAt](result-defs-result-properties-failed_at-oneof-failedat.md "check type definition")

*   [Untitled null in Result](result-defs-result-properties-failed_at-oneof-1.md "check type definition")

As far as I can see, jsonschema2md looks for "type": ["string", "null"] to mark a field as nullable.

I don't know what's the correct way to do it.
Is there anyway to get this library to output "type": ["string", "null"] instead of oneOf?

`oneof_type` prevents interpretation of other keyword tags

because oneof_type doesnt write to the Type property of a Schema object, the switch statement in structKeywordsFromTags doesn't interpret any other tags. so a set of tags like

Field1 *string `jsonschema:"oneof_type=string;null,enum=VAL1,enum=VAL2"`

will not parse the enum tags, because oneof_type sets the OneOf property instead of the Type property

in this particular example, its arguable that the enum values should not be parsed, but imo if null was an enum value as well i would say that they should be

Feature request: support oneof_ref

It would be nice to use oneof_ref such that a field could be one of several already-defined objects, as suggested here:
https://stackoverflow.com/questions/57414600/json-schema-oneof-with-ref-to-wildcard-path

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$defs": {
    "ipv4": {...},
    "ipv6": {...}
    "ipAddress": {
      "oneOf": [{
          "$ref": "#/$defs/ipv4"
      },{
          "$ref": "#/$defs/ipv6"
      }]
    }
  }
  "properties": {
    "anIPAddress": {
      "$ref": "#/$defs/ipAddress"
    }
  }
}

and the Go code would look something like:

...
	IPAddress    any    `json:"ipAddress" jsonschema:"oneof_ref=#/$defs/ipv4;#/$defs/ipv6"`
...

I'll try to put together a PR.

Transform struct keys before generating the JSON schema

In my application, I transform struct keys to snake_case before writing a JSON file.

For this, I use json-iterator's RegisterExtension to rename keys to snake_case

But right now, it doesn't seem possible to reflect that using this package.

What I'd like is a new option for the Reflector type, something like TransformKeys, of type func(string) string that gets run on every struct key before generating the schema.

This would be like a "key name" equivalent of Namer, basically.

I might actually do a PR, it doesn't seem that complicated to implement.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.