Categorygithub.com/swaggest/jsonschema-go
modulepackage
0.3.73
Repository: https://github.com/swaggest/jsonschema-go.git
Documentation: pkg.go.dev

# README

JSON Schema structures for Go

Build Status Coverage Status GoDevDoc time tracker Code lines Comments

This library provides Go structures to marshal/unmarshal and reflect JSON Schema documents.

Reflector

Documentation.

type MyStruct struct {
    Amount float64  `json:"amount" minimum:"10.5" example:"20.6" required:"true"`
    Abc    string   `json:"abc" pattern:"[abc]"`
    _      struct{} `additionalProperties:"false"`                   // Tags of unnamed field are applied to parent schema.
    _      struct{} `title:"My Struct" description:"Holds my data."` // Multiple unnamed fields can be used.
}

reflector := jsonschema.Reflector{}

schema, err := reflector.Reflect(MyStruct{})
if err != nil {
    log.Fatal(err)
}

j, err := json.MarshalIndent(schema, "", " ")
if err != nil {
    log.Fatal(err)
}

fmt.Println(string(j))

// Output:
// {
//  "title": "My Struct",
//  "description": "Holds my data.",
//  "required": [
//   "amount"
//  ],
//  "additionalProperties": false,
//  "properties": {
//   "abc": {
//    "pattern": "[abc]",
//    "type": "string"
//   },
//   "amount": {
//    "examples": [
//     20.6
//    ],
//    "minimum": 10.5,
//    "type": "number"
//   }
//  },
//  "type": "object"
// }

Customization

By default, JSON Schema is generated from Go struct field types and tags. It works well for the majority of cases, but if it does not there are rich customization options.

Field tags

type MyObj struct {
   BoundedNumber int `query:"boundedNumber" minimum:"-100" maximum:"100"`
   SpecialString string `json:"specialString" pattern:"^[a-z]{4}$" minLength:"4" maxLength:"4"`
}

Note: field tags are only applied to inline schemas, if you use named type then referenced schema will be created and tags will be ignored. This happens because referenced schema can be used in multiple fields with conflicting tags, therefore customization of referenced schema has to done on the type itself via RawExposer, Exposer or Preparer.

Each tag value has to be put in double quotes ("123").

These tags can be used:

Unnamed fields can be used to configure parent schema:

type MyObj struct {
   BoundedNumber int `query:"boundedNumber" minimum:"-100" maximum:"100"`
   SpecialString string `json:"specialString" pattern:"^[a-z]{4}$" minLength:"4" maxLength:"4"`
   _             struct{} `additionalProperties:"false" description:"MyObj is my object."`
}

In case of a structure with multiple name tags, you can enable filtering of unnamed fields with ReflectContext.UnnamedFieldWithTag option and add matching name tags to structure (e.g. query:"_").

type MyObj struct {
   BoundedNumber int `query:"boundedNumber" minimum:"-100" maximum:"100"`
   SpecialString string `json:"specialString" pattern:"^[a-z]{4}$" minLength:"4" maxLength:"4"`
   // These parent schema tags would only be applied to `query` schema reflection (not for `json`).
   _ struct{} `query:"_" additionalProperties:"false" description:"MyObj is my object."`
}

Implementing interfaces on a type

There are a few interfaces that can be implemented on a type to customize JSON Schema generation.

  • Preparer allows to change generated JSON Schema.
  • Exposer overrides generated JSON Schema.
  • RawExposer overrides generated JSON Schema.
  • Described exposes description.
  • Titled exposes title.
  • Enum exposes enum values.
  • NamedEnum exposes enum values with names.
  • SchemaInliner inlines schema without creating a definition.
  • IgnoreTypeName, when implemented on a mapped type forces the use of original type for definition name.
  • EmbedReferencer, when implemented on an embedded field type, makes an allOf reference to that type definition.

And a few interfaces to expose subschemas (anyOf, allOf, oneOf, not and if, then, else).

There are also helper functions jsonschema.AllOf, jsonschema.AnyOf, jsonschema.OneOf to create exposer instance from multiple values.

Configuring the reflector

Additional centralized configuration is available with jsonschema.ReflectContext and Reflect options.

Virtual structure

Sometimes it is impossible to define a static Go struct, for example when fields are only known at runtime. Yet, you may need to include such fields in JSON schema reflection pipeline.

For any reflected value, standalone or nested, you can define a virtual structure that would be treated as a native Go struct.

s := jsonschema.Struct{}
s.SetTitle("Test title")
s.SetDescription("Test description")
s.DefName = "TestStruct"
s.Nullable = true

s.Fields = append(s.Fields, jsonschema.Field{
    Name:  "Foo",
    Value: "abc",
    Tag:   `json:"foo" minLength:"3"`,
})

r := jsonschema.Reflector{}
schema, _ := r.Reflect(s)
j, _ := assertjson.MarshalIndentCompact(schema, "", " ", 80)

fmt.Println("Standalone:", string(j))

type MyStruct struct {
    jsonschema.Struct // Can be embedded.

    Bar int `json:"bar"`

    Nested jsonschema.Struct `json:"nested"` // Can be nested.
}

ms := MyStruct{}
ms.Nested = s
ms.Struct = s

schema, _ = r.Reflect(ms)
j, _ = assertjson.MarshalIndentCompact(schema, "", " ", 80)

fmt.Println("Nested:", string(j))

// Output:
// Standalone: {
//  "title":"Test title","description":"Test description",
//  "properties":{"foo":{"minLength":3,"type":"string"}},"type":"object"
// }
// Nested: {
//  "definitions":{
//   "TestStruct":{
//    "title":"Test title","description":"Test description",
//    "properties":{"foo":{"minLength":3,"type":"string"}},"type":"object"
//   }
//  },
//  "properties":{
//   "bar":{"type":"integer"},"foo":{"minLength":3,"type":"string"},
//   "nested":{"$ref":"#/definitions/TestStruct"}
//  },
//  "type":"object"
// }

Custom Tags For Schema Definitions

If you're using additional libraries for validation, like for example go-playground/validator, you may want to infer validation rules into documented JSON schema.

type My struct {
    Foo *string `json:"foo" validate:"required"`
}

Normally, validate:"required" is not recognized, and you'd need to add required:"true" to have the rule exported to JSON schema.

However, it is possible to extend reflection with custom processing with InterceptProp option.

s, err := r.Reflect(My{}, jsonschema.InterceptProp(func(params jsonschema.InterceptPropParams) error {
    if !params.Processed {
        return nil
    }

    if v, ok := params.Field.Tag.Lookup("validate"); ok {
        if strings.Contains(v, "required") {
            params.ParentSchema.Required = append(params.ParentSchema.Required, params.Name)
        }
    }

    return nil
}))

# Functions

AllOf exposes list of values as JSON "allOf" schema.
AnyOf exposes list of values as JSON "anyOf" schema.
CollectDefinitions enables collecting definitions with provided func instead of result schema.
DefinitionsPrefix sets up location for newly created references, default "#/definitions/".
InlineRefs prevents references.
InterceptDefName allows modifying reflected definition names.
InterceptNullability add hook to customize nullability.
InterceptProp adds a hook to customize property schema.
InterceptProperty adds hook to customize property schema.
InterceptSchema adds hook to customize schema.
InterceptType adds hook to customize schema.
MakePropertyNameMapping makes property name mapping from struct value suitable for jsonschema.PropertyNameMapping.
OneOf exposes list of values as JSON "oneOf" schema.
ProcessWithoutTags enables processing fields without any tags specified.
PropertyNameMapping enables property name mapping from a struct field name.
PropertyNameTag sets up which field tag to use for property name, default "json".
RootNullable enables nullability (by pointer) for root schema, disabled by default.
RootRef enables referencing root schema.
SkipEmbeddedMapsSlices disables shortcutting into embedded maps and slices.
SkipUnsupportedProperties skips properties with unsupported types (func, chan, etc...) instead of failing.
StripDefinitionNamePrefix checks if definition name has any of provided prefixes and removes first encountered.

# Constants

SimpleType values enumeration.
SimpleType values enumeration.
DateLayout describes date format.
ErrSkipProperty indicates that property should not be added to object.
SimpleType values enumeration.
SimpleType values enumeration.
SimpleType values enumeration.
SimpleType values enumeration.
SimpleType values enumeration.
XEnumNames is the name of JSON property to store names of enumerated values.

# Structs

DependenciesAdditionalProperties structure is generated from "#[object]->dependencies->additionalProperties".
Field mimics Go reflect.StructField for purposes of schema reflection.
InterceptNullabilityParams defines InterceptNullabilityFunc parameters.
InterceptPropParams defines InterceptPropFunc parameters.
InterceptSchemaParams defines InterceptSchemaFunc parameters.
Items structure is generated from "#[object]->items".
Ref is a definition reference.
ReflectContext accompanies single reflect operation.
Reflector creates JSON Schemas from Go values.
Schema structure is generated from "#[object]".
SchemaOrBool structure is generated from "#".
Struct mimics Go struct to allow schema reflection on virtual struct type.
Type structure is generated from "#[object]->type".

# Interfaces

AllOfExposer exposes "allOf" items as list of samples.
AnyOfExposer exposes "anyOf" items as list of samples.
Described exposes description.
ElseExposer exposes "else" schema as a sample.
EmbedReferencer is a marker interface to enable reference to embedded struct type.
Enum returns the enumerated acceptable values.
Exposer exposes JSON Schema.
IfExposer exposes "if" schema as a sample.
IgnoreTypeName is a marker interface to ignore type name of mapped value and use original.
NamedEnum returns the enumerated acceptable values with according string names.
NotExposer exposes "not" schema as a sample.
OneOfExposer exposes "oneOf" items as list of samples.
Preparer alters reflected JSON Schema.
RawExposer exposes JSON Schema as JSON bytes.
SchemaInliner is a marker interface to inline schema without creating a definition.
ThenExposer exposes "then" schema as a sample.
Titled exposes title.

# Type aliases

Date is a date represented in YYYY-MM-DD format.
InterceptNullabilityFunc can intercept schema reflection to control or modify nullability state.
InterceptPropertyFunc can intercept field reflection to control or modify schema.
InterceptPropFunc can intercept field reflection to control or modify schema.
InterceptSchemaFunc can intercept type reflection to control or modify schema.
InterceptTypeFunc can intercept type reflection to control or modify schema.
SimpleType is an enum type.