jsonschema

package module
v0.1.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 3, 2023 License: MIT Imports: 19 Imported by: 1

README

Go JSON Schema Reflection

Lint Test Go Go Report Card GoDoc Latest Tag

This package can be used to generate JSON Schemas from Go types through reflection.

  • Supports arbitrarily complex types, including any, maps, slices, etc.
  • Supports json-schema features such as minLength, maxLength, pattern, format, etc.
  • Supports simple string and numeric enums.
  • Supports custom property fields via the jsonschema_extras struct tag.

This repository is a fork of the original jsonschema by @alecthomas. At Invopop we use jsonschema as a cornerstone in our GOBL library, and wanted to be able to continue building and adding features without taking up Alec's time. There have been a few significant changes that probably mean this version is a not compatible with with Alec's:

  • The original was stuck on the draft-04 version of JSON Schema, we've now moved to the latest JSON Schema Draft 2020-12.
  • Schema IDs are added automatically from the current Go package's URL in order to be unique, and can be disabled with the Anonymous option.
  • Support for the FullyQualifyTypeName option has been removed. If you have conflicts, you should use multiple schema files with different IDs, set the DoNotReference option to true to hide definitions completely, or add your own naming strategy using the Namer property.
  • Support for yaml tags and related options has been dropped for the sake of simplification. There were a few inconsistencies around this that have now been fixed.

Versions

This project is still under v0 scheme, as per Go convention, breaking changes are likely. Please pin go modules to branches, and reach out if you think something can be improved.

Example

The following Go type:

type TestUser struct {
  ID            int                    `json:"id"`
  Name          string                 `json:"name" jsonschema:"title=the name,description=The name of a friend,example=joe,example=lucy,default=alex"`
  Friends       []int                  `json:"friends,omitempty" jsonschema_description:"The list of IDs, omitted when empty"`
  Tags          map[string]any `json:"tags,omitempty" jsonschema_extras:"a=b,foo=bar,foo=bar1"`
  BirthDate     time.Time              `json:"birth_date,omitempty" jsonschema:"oneof_required=date"`
  YearOfBirth   string                 `json:"year_of_birth,omitempty" jsonschema:"oneof_required=year"`
  Metadata      any            `json:"metadata,omitempty" jsonschema:"oneof_type=string;array"`
  FavColor      string                 `json:"fav_color,omitempty" jsonschema:"enum=red,enum=green,enum=blue"`
}

Results in following JSON Schema:

jsonschema.Reflect(&TestUser{})
{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/SampleUser",
  "$defs": {
    "SampleUser": {
      "oneOf": [
        {
          "required": ["birth_date"],
          "title": "date"
        },
        {
          "required": ["year_of_birth"],
          "title": "year"
        }
      ],
      "properties": {
        "id": {
          "type": "integer"
        },
        "name": {
          "type": "string",
          "title": "the name",
          "description": "The name of a friend",
          "default": "alex",
          "examples": ["joe", "lucy"]
        },
        "friends": {
          "items": {
            "type": "integer"
          },
          "type": "array",
          "description": "The list of IDs, omitted when empty"
        },
        "tags": {
          "type": "object",
          "a": "b",
          "foo": ["bar", "bar1"]
        },
        "birth_date": {
          "type": "string",
          "format": "date-time"
        },
        "year_of_birth": {
          "type": "string"
        },
        "metadata": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array"
            }
          ]
        },
        "fav_color": {
          "type": "string",
          "enum": ["red", "green", "blue"]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": ["id", "name"]
    }
  }
}

YAML

Support for yaml tags has now been removed. If you feel very strongly about this, we've opened a discussion to hear your comments: https://github.com/authelia/jsonschema/discussions/28

The recommended approach if you need to deal with YAML data is to first convert to JSON. The invopop/yaml library will make this trivial.

Configurable behaviour

The behaviour of the schema generator can be altered with parameters when a jsonschema.Reflector instance is created.

ExpandedStruct

If set to true, makes the top level struct not to reference itself in the definitions. But type passed should be a struct type.

eg.

type GrandfatherType struct {
	FamilyName string `json:"family_name" jsonschema:"required"`
}

type SomeBaseType struct {
	SomeBaseProperty int `json:"some_base_property"`
	// The jsonschema required tag is nonsensical for private and ignored properties.
	// Their presence here tests that the fields *will not* be required in the output
	// schema, even if they are tagged required.
	somePrivateBaseProperty            string `json:"i_am_private" jsonschema:"required"`
	SomeIgnoredBaseProperty            string `json:"-" jsonschema:"required"`
	SomeSchemaIgnoredProperty          string `jsonschema:"-,required"`
	SomeUntaggedBaseProperty           bool   `jsonschema:"required"`
	someUnexportedUntaggedBaseProperty bool
	Grandfather                        GrandfatherType `json:"grand"`
}

will output:

{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "required": ["some_base_property", "grand", "SomeUntaggedBaseProperty"],
  "properties": {
    "SomeUntaggedBaseProperty": {
      "type": "boolean"
    },
    "grand": {
      "$schema": "http://json-schema.org/draft/2020-12/schema",
      "$ref": "#/definitions/GrandfatherType"
    },
    "some_base_property": {
      "type": "integer"
    }
  },
  "type": "object",
  "$defs": {
    "GrandfatherType": {
      "required": ["family_name"],
      "properties": {
        "family_name": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "type": "object"
    }
  }
}
Using Go Comments

Writing a good schema with descriptions inside tags can become cumbersome and tedious, especially if you already have some Go comments around your types and field definitions. If you'd like to take advantage of these existing comments, you can use the AddGoComments(base, path string) method that forms part of the reflector to parse your go files and automatically generate a dictionary of Go import paths, types, and fields, to individual comments. These will then be used automatically as description fields, and can be overridden with a manual definition if needed.

Take a simplified example of a User struct which for the sake of simplicity we assume is defined inside this package:

package main

// User is used as a base to provide tests for comments.
type User struct {
	// Unique sequential identifier.
	ID int `json:"id" jsonschema:"required"`
	// Name of the user
	Name string `json:"name"`
}

To get the comments provided into your JSON schema, use a regular Reflector and add the go code using an import module URL and path. Fully qualified go module paths cannot be determined reliably by the go/parser library, so we need to introduce this manually:

r := new(Reflector)
if err := r.AddGoComments("github.com/authelia/jsonschema", "./"); err != nil {
  // deal with error
}
s := r.Reflect(&User{})
// output

Expect the results to be similar to:

{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/User",
  "$defs": {
    "User": {
      "required": ["id"],
      "properties": {
        "id": {
          "type": "integer",
          "description": "Unique sequential identifier."
        },
        "name": {
          "type": "string",
          "description": "Name of the user"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "User is used as a base to provide tests for comments."
    }
  }
}
Custom Key Naming

In some situations, the keys actually used to write files are different from Go structs'.

This is often the case when writing a configuration file to YAML or JSON from a Go struct, or when returning a JSON response for a Web API: APIs typically use snake_case, while Go uses PascalCase.

You can pass a func(string) string function to Reflector's KeyNamer option to map Go field names to JSON key names and reflect the aforementioned transformations, without having to specify json:"..." on every struct field.

For example, consider the following struct

type User struct {
  GivenName       string
  PasswordSalted  []byte `json:"salted_password"`
}

We can transform field names to snake_case in the generated JSON schema:

r := new(jsonschema.Reflector)
r.KeyNamer = strcase.SnakeCase // from package github.com/stoewer/go-strcase

r.Reflect(&User{})

Will yield

  {
    "$schema": "http://json-schema.org/draft/2020-12/schema",
    "$ref": "#/$defs/User",
    "$defs": {
      "User": {
        "properties": {
-         "GivenName": {
+         "given_name": {
            "type": "string"
          },
          "salted_password": {
            "type": "string",
            "contentEncoding": "base64"
          }
        },
        "additionalProperties": false,
        "type": "object",
-       "required": ["GivenName", "salted_password"]
+       "required": ["given_name", "salted_password"]
      }
    }
  }

As you can see, if a field name has a json:"" tag set, the key argument to KeyNamer will have the value of that tag.

Custom Type Definitions

Sometimes it can be useful to have custom JSON Marshal and Unmarshal methods in your structs that automatically convert for example a string into an object.

To override auto-generating an object type for your type, implement the JSONSchema() *Schema method and whatever is defined will be provided in the schema definitions.

Take the following simplified example of a CompactDate that only includes the Year and Month:

type CompactDate struct {
	Year  int
	Month int
}

func (d *CompactDate) UnmarshalJSON(data []byte) error {
  if len(data) != 9 {
    return errors.New("invalid compact date length")
  }
  var err error
  d.Year, err = strconv.Atoi(string(data[1:5]))
  if err != nil {
    return err
  }
  d.Month, err = strconv.Atoi(string(data[7:8]))
  if err != nil {
    return err
  }
  return nil
}

func (d *CompactDate) MarshalJSON() ([]byte, error) {
  buf := new(bytes.Buffer)
  buf.WriteByte('"')
  buf.WriteString(fmt.Sprintf("%d-%02d", d.Year, d.Month))
  buf.WriteByte('"')
  return buf.Bytes(), nil
}

func (CompactDate) JSONSchema() *Schema {
	return &Schema{
		Type:        "string",
		Title:       "Compact Date",
		Description: "Short date that only includes year and month",
		Pattern:     "^[0-9]{4}-[0-1][0-9]$",
	}
}

The resulting schema generated for this struct would look like:

{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/CompactDate",
  "$defs": {
    "CompactDate": {
      "pattern": "^[0-9]{4}-[0-1][0-9]$",
      "type": "string",
      "title": "Compact Date",
      "description": "Short date that only includes year and month"
    }
  }
}

Documentation

Overview

Package jsonschema uses reflection to generate JSON Schemas from Go types [1].

If json tags are present on struct fields, they will be used to infer property names and if a property is required (omitempty is present).

[1] http://json-schema.org/latest/json-schema-validation.html

Index

Examples

Constants

View Source
const (
	// TypeString represents the string JSON Schema type.
	// See https://json-schema.org/understanding-json-schema/reference/string.html#string for more information.
	TypeString = "string"

	// TypeNumber represents the numeric JSON Schema type.
	// See https://json-schema.org/understanding-json-schema/reference/numeric.html#number for more information.
	TypeNumber = "number"

	// TypeInteger represents the integer JSON Schema type.
	// See https://json-schema.org/understanding-json-schema/reference/numeric.html#integer for more information.
	TypeInteger = "integer"

	// TypeObject represents the object JSON Schema type.
	// See https://json-schema.org/understanding-json-schema/reference/object.html#object for more information.
	TypeObject = "object"

	// TypeArray represents the object JSON Schema type.
	// See https://json-schema.org/understanding-json-schema/reference/array.html#array for more information.
	TypeArray = "array"

	// TypeBoolean represents the boolean JSON Schema type.
	// See https://json-schema.org/understanding-json-schema/reference/boolean.html#boolean for more information.
	TypeBoolean = "boolean"

	// TypeNull represents the null JSON Schema type.
	// See https://json-schema.org/understanding-json-schema/reference/null.html#null for more information.
	TypeNull = "null"
)
View Source
const (
	FormatStringDateTime                  = "date-time"
	FormatStringTime                      = "time"
	FormatStringDate                      = "date"
	FormatStringDuration                  = "duration"
	FormatStringEmail                     = "email"
	FormatStringInternationalizedEmail    = "idn-email"
	FormatStringHostname                  = "hostname"
	FormatStringInternationalizedHostname = "idn-hostname"
	FormatStringIPv4                      = "ipv4"
	FormatStringIPv6                      = "ipv6"
	FormatStringUUID                      = "uuid"
	FormatStringURI                       = "uri"
	FormatStringURIReference              = "uri-reference"
	FormatStringURITemplate               = "uri-template"
	FormatStringIRI                       = "iri"
	FormatStringIRIReference              = "iri-reference"
	FormatStringRegex                     = "regex"
	FormatStringJSONPointer               = "json-pointer"
	FormatStringRelativeJSONPointer       = "relative-json-pointer"
)

A built-in string format. See https://json-schema.org/understanding-json-schema/reference/string.html#built-in-formats for more information.

Variables

View Source
var (
	// TrueSchema defines a schema with a true value
	TrueSchema = &Schema{boolean: &[]bool{true}[0]}
	// FalseSchema defines a schema with a false value
	FalseSchema = &Schema{boolean: &[]bool{false}[0]}
)
View Source
var Version = "https://json-schema.org/draft/2020-12/schema"

Version is the JSON Schema version.

Functions

func ExtractGoComments

func ExtractGoComments(base, path string, commentMap map[string]string) error

ExtractGoComments will read all the go files contained in the provided path, including sub-directories, in order to generate a dictionary of comments associated with Types and Fields. The results will be added to the `commentsMap` provided in the parameters and expected to be used for Schema "description" fields.

The `go/parser` library is used to extract all the comments and unfortunately doesn't have a built-in way to determine the fully qualified name of a package. The `base` paremeter, the URL used to import that package, is thus required to be able to match reflected types.

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.

func ToSnakeCase

func ToSnakeCase(str string) string

ToSnakeCase converts the provided string into snake case using dashes. This is useful for Schema IDs and definitions to be coherent with common JSON Schema examples.

Types

type Definitions

type Definitions map[string]*Schema

Definitions hold schema definitions. http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.26 RFC draft-wright-json-schema-validation-00, section 5.26

type ID

type ID string

ID represents a Schema ID type which should always be a URI. See draft-bhutton-json-schema-00 section 8.2.1

const EmptyID ID = ""

EmptyID is used to explicitly define an ID with no value.

func (ID) Add

func (id ID) Add(path string) ID

Add appends the provided path to the id, and removes any anchor data that might be there.

func (ID) Anchor

func (id ID) Anchor(name string) ID

Anchor sets the anchor part of the schema URI.

func (ID) Base

func (id ID) Base() ID

Base removes any anchor information from the schema

func (ID) Def

func (id ID) Def(name string) ID

Def adds or replaces a definition identifier.

func (ID) String

func (id ID) String() string

String provides string version of ID

func (ID) Validate

func (id ID) Validate() error

Validate is used to check if the ID looks like a proper schema. This is done by parsing the ID as a URL and checking it has all the relevant parts.

type Reflector

type Reflector struct {
	// BaseSchemaID defines the URI that will be used as a base to determine Schema
	// IDs for models. For example, a base Schema ID of `https://invopop.com/schemas`
	// when defined with a struct called `User{}`, will result in a schema with an
	// ID set to `https://invopop.com/schemas/user`.
	//
	// If no `BaseSchemaID` is provided, we'll take the type's complete package path
	// and use that as a base instead. Set `Anonymous` to try if you do not want to
	// include a schema ID.
	BaseSchemaID ID

	// Anonymous when true will hide the auto-generated Schema ID and provide what is
	// known as an "anonymous schema". As a rule, this is not recommended.
	Anonymous bool

	// AssignAnchor when true will use the original struct's name as an anchor inside
	// every definition, including the root schema. These can be useful for having a
	// reference to the original struct's name in CamelCase instead of the snake-case used
	// by default for URI compatibility.
	//
	// Anchors do not appear to be widely used out in the wild, so at this time the
	// anchors themselves will not be used inside generated schema.
	AssignAnchor bool

	// AllowAdditionalProperties will cause the Reflector to generate a schema
	// without additionalProperties set to 'false' for all struct types. This means
	// the presence of additional keys in JSON objects will not cause validation
	// to fail. Note said additional keys will simply be dropped when the
	// validated JSON is unmarshaled.
	AllowAdditionalProperties bool

	// RequiredFromJSONSchemaTags will cause the Reflector to generate a schema
	// that requires any key tagged with `jsonschema:required`, overriding the
	// default of requiring any key *not* tagged with `json:,omitempty`.
	RequiredFromJSONSchemaTags bool

	// Do not reference definitions. This will remove the top-level $defs map and
	// instead cause the entire structure of types to be output in one tree. The
	// list of type definitions (`$defs`) will not be included.
	DoNotReference bool

	// ExpandedStruct when true will include the reflected type's definition in the
	// root as opposed to a definition with a reference.
	ExpandedStruct bool

	// IgnoredTypes defines a slice of types that should be ignored in the schema,
	// switching to just allowing additional properties instead.
	IgnoredTypes []any

	// Lookup allows a function to be defined that will provide a custom mapping of
	// types to Schema IDs. This allows existing schema documents to be referenced
	// by their ID instead of being embedded into the current schema definitions.
	// Reflected types will never be pointers, only underlying elements.
	Lookup func(reflect.Type) ID

	// Mapper is a function that can be used to map custom Go types to jsonschema schemas.
	Mapper func(reflect.Type) *Schema

	// Namer allows customizing of type names. The default is to use the type's name
	// provided by the reflect package.
	Namer func(reflect.Type) string

	// Requirer custom the requiring of any struct field, its behaves after the
	// `json:,omitempty` or `jsonschema:required` parsed.
	Requirer func(reflect.StructField, bool) bool

	// KeyNamer allows customizing of key names.
	// The default is to use the key's name as is, or the json tag if present.
	// If a json tag is present, KeyNamer will receive the tag's name as an argument, not the original key name.
	KeyNamer func(string) string

	// AdditionalFields allows adding structfields for a given type
	AdditionalFields func(reflect.Type) []reflect.StructField

	// CommentMap is a dictionary of fully qualified go types and fields to comment
	// strings that will be used if a description has not already been provided in
	// the tags. Types and fields are added to the package path using "." as a
	// separator.
	//
	// Type descriptions should be defined like:
	//
	//   map[string]string{"github.com/authelia/jsonschema.Reflector": "A Reflector reflects values into a Schema."}
	//
	// And Fields defined as:
	//
	//   map[string]string{"github.com/authelia/jsonschema.Reflector.DoNotReference": "Do not reference definitions."}
	//
	// See also: AddGoComments
	CommentMap map[string]string
}

A Reflector reflects values into a Schema.

func (*Reflector) AddGoComments

func (r *Reflector) AddGoComments(base, path string) error

AddGoComments will update the reflectors comment map with all the comments found in the provided source directories. See the #ExtractGoComments method for more details.

func (*Reflector) Reflect

func (r *Reflector) Reflect(v any) *Schema

Reflect reflects to Schema from a value.

func (*Reflector) ReflectFromType

func (r *Reflector) ReflectFromType(t reflect.Type) *Schema

ReflectFromType generates root schema

func (*Reflector) SetBaseSchemaID

func (r *Reflector) SetBaseSchemaID(id string)

SetBaseSchemaID is a helper use to be able to set the reflectors base schema ID from a string as opposed to then ID instance.

type Schema

type Schema struct {
	// RFC draft-bhutton-json-schema-00
	Version     string      `json:"$schema,omitempty"`     // section 8.1.1
	ID          ID          `json:"$id,omitempty"`         // section 8.2.1
	Anchor      string      `json:"$anchor,omitempty"`     // section 8.2.2
	Ref         string      `json:"$ref,omitempty"`        // section 8.2.3.1
	DynamicRef  string      `json:"$dynamicRef,omitempty"` // section 8.2.3.2
	Definitions Definitions `json:"$defs,omitempty"`       // section 8.2.4
	Comments    string      `json:"$comment,omitempty"`    // section 8.3
	// RFC draft-bhutton-json-schema-00 section 10.2.1 (Sub-schemas with logic)
	AllOf []*Schema `json:"allOf,omitempty"` // section 10.2.1.1
	AnyOf []*Schema `json:"anyOf,omitempty"` // section 10.2.1.2
	OneOf []*Schema `json:"oneOf,omitempty"` // section 10.2.1.3
	Not   *Schema   `json:"not,omitempty"`   // section 10.2.1.4
	// RFC draft-bhutton-json-schema-00 section 10.2.2 (Apply sub-schemas conditionally)
	If               *Schema            `json:"if,omitempty"`               // section 10.2.2.1
	Then             *Schema            `json:"then,omitempty"`             // section 10.2.2.2
	Else             *Schema            `json:"else,omitempty"`             // section 10.2.2.3
	DependentSchemas map[string]*Schema `json:"dependentSchemas,omitempty"` // section 10.2.2.4
	// RFC draft-bhutton-json-schema-00 section 10.3.1 (arrays)
	PrefixItems []*Schema `json:"prefixItems,omitempty"` // section 10.3.1.1
	Items       *Schema   `json:"items,omitempty"`       // section 10.3.1.2  (replaces additionalItems)
	Contains    *Schema   `json:"contains,omitempty"`    // section 10.3.1.3
	// RFC draft-bhutton-json-schema-00 section 10.3.2 (sub-schemas)
	Properties           *orderedmap.OrderedMap `json:"properties,omitempty"`           // section 10.3.2.1
	PatternProperties    map[string]*Schema     `json:"patternProperties,omitempty"`    // section 10.3.2.2
	AdditionalProperties *Schema                `json:"additionalProperties,omitempty"` // section 10.3.2.3
	PropertyNames        *Schema                `json:"propertyNames,omitempty"`        // section 10.3.2.4
	// RFC draft-bhutton-json-schema-validation-00, section 6
	Type              string              `json:"type,omitempty"`              // section 6.1.1
	Enum              []any               `json:"enum,omitempty"`              // section 6.1.2
	Const             any                 `json:"const,omitempty"`             // section 6.1.3
	MultipleOf        int                 `json:"multipleOf,omitempty"`        // section 6.2.1
	Maximum           int                 `json:"maximum,omitempty"`           // section 6.2.2
	ExclusiveMaximum  bool                `json:"exclusiveMaximum,omitempty"`  // section 6.2.3
	Minimum           int                 `json:"minimum,omitempty"`           // section 6.2.4
	ExclusiveMinimum  bool                `json:"exclusiveMinimum,omitempty"`  // section 6.2.5
	MaxLength         int                 `json:"maxLength,omitempty"`         // section 6.3.1
	MinLength         int                 `json:"minLength,omitempty"`         // section 6.3.2
	Pattern           string              `json:"pattern,omitempty"`           // section 6.3.3
	MaxItems          int                 `json:"maxItems,omitempty"`          // section 6.4.1
	MinItems          int                 `json:"minItems,omitempty"`          // section 6.4.2
	UniqueItems       bool                `json:"uniqueItems,omitempty"`       // section 6.4.3
	MaxContains       uint                `json:"maxContains,omitempty"`       // section 6.4.4
	MinContains       uint                `json:"minContains,omitempty"`       // section 6.4.5
	MaxProperties     int                 `json:"maxProperties,omitempty"`     // section 6.5.1
	MinProperties     int                 `json:"minProperties,omitempty"`     // section 6.5.2
	Required          []string            `json:"required,omitempty"`          // section 6.5.3
	DependentRequired map[string][]string `json:"dependentRequired,omitempty"` // section 6.5.4
	// RFC draft-bhutton-json-schema-validation-00, section 7
	Format string `json:"format,omitempty"`
	// RFC draft-bhutton-json-schema-validation-00, section 8
	ContentEncoding  string  `json:"contentEncoding,omitempty"`  // section 8.3
	ContentMediaType string  `json:"contentMediaType,omitempty"` // section 8.4
	ContentSchema    *Schema `json:"contentSchema,omitempty"`    // section 8.5
	// RFC draft-bhutton-json-schema-validation-00, section 9
	Title       string `json:"title,omitempty"`       // section 9.1
	Description string `json:"description,omitempty"` // section 9.1
	Default     any    `json:"default,omitempty"`     // section 9.2
	Deprecated  bool   `json:"deprecated,omitempty"`  // section 9.3
	ReadOnly    bool   `json:"readOnly,omitempty"`    // section 9.4
	WriteOnly   bool   `json:"writeOnly,omitempty"`   // section 9.4
	Examples    []any  `json:"examples,omitempty"`    // section 9.5

	Extras map[string]any `json:"-"`
	// contains filtered or unexported fields
}

Schema represents a JSON Schema object type. RFC draft-bhutton-json-schema-00 section 4.3

func Reflect

func Reflect(v any) *Schema

Reflect reflects to Schema from a value using the default Reflector

Example
package main

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/authelia/jsonschema"
)

type SampleUser struct {
	ID          int            `json:"id"`
	Name        string         `json:"name" jsonschema:"title=the name,description=The name of a friend,example=joe,example=lucy,default=alex"`
	Friends     []int          `json:"friends,omitempty" jsonschema_description:"The list of IDs, omitted when empty"`
	Tags        map[string]any `json:"tags,omitempty" jsonschema_extras:"a=b,foo=bar,foo=bar1"`
	BirthDate   time.Time      `json:"birth_date,omitempty" jsonschema:"oneof_required=date"`
	YearOfBirth string         `json:"year_of_birth,omitempty" jsonschema:"oneof_required=year"`
	Metadata    any            `json:"metadata,omitempty" jsonschema:"oneof_type=string;array"`
	FavColor    string         `json:"fav_color,omitempty" jsonschema:"enum=red,enum=green,enum=blue"`
}

func main() {
	s := jsonschema.Reflect(&SampleUser{})
	data, err := json.MarshalIndent(s, "", "  ")
	if err != nil {
		panic(err.Error())
	}
	fmt.Println(string(data))
}
Output:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/authelia/jsonschema_test/sample-user",
  "$ref": "#/$defs/SampleUser",
  "$defs": {
    "SampleUser": {
      "oneOf": [
        {
          "required": [
            "birth_date"
          ],
          "title": "date"
        },
        {
          "required": [
            "year_of_birth"
          ],
          "title": "year"
        }
      ],
      "properties": {
        "id": {
          "type": "integer"
        },
        "name": {
          "type": "string",
          "title": "the name",
          "description": "The name of a friend",
          "default": "alex",
          "examples": [
            "joe",
            "lucy"
          ]
        },
        "friends": {
          "items": {
            "type": "integer"
          },
          "type": "array",
          "description": "The list of IDs, omitted when empty"
        },
        "tags": {
          "type": "object",
          "a": "b",
          "foo": [
            "bar",
            "bar1"
          ]
        },
        "birth_date": {
          "type": "string",
          "format": "date-time"
        },
        "year_of_birth": {
          "type": "string"
        },
        "metadata": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array"
            }
          ]
        },
        "fav_color": {
          "type": "string",
          "enum": [
            "red",
            "green",
            "blue"
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "id",
        "name"
      ]
    }
  }
}

func ReflectFromType

func ReflectFromType(t reflect.Type) *Schema

ReflectFromType generates root schema using the default Reflector

func (*Schema) MarshalJSON

func (t *Schema) MarshalJSON() ([]byte, error)

func (*Schema) UnmarshalJSON

func (t *Schema) UnmarshalJSON(data []byte) error

UnmarshalJSON is used to parse a schema object or boolean.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL