schema

package
v1.15.7 Latest Latest
Warning

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

Go to latest
Published: Feb 3, 2024 License: Apache-2.0 Imports: 11 Imported by: 0

README

简介

该schema包用于将Go Struct中的注解用反射的方式生成json schema,用于render。

来自于 github.com/danielgtaylor/huma/schema

为保持go结构体字段顺序以及map键值对的顺序,需要对源码进行修改。

主要修改

  • properties改成数组,并且子schema需要包含name和required,同时required从数组改成布尔值
  • 新类型map,实际为数组
  • 新增dependencies关键字
  • 新增skill自定义关键字
  • 新增switch自定义关键字
  • 新增label自定义关键字
  • 新增eo:type自定义关键字
  • 新增ui:sort自定义关键字

使用说明

//传入目标结构体的反射type,若对该结构体内的field有dependencies依赖性需求,可以传入非空的schema结构体
func Generate(t reflect.Type, schema *Schema) (*Schema, error)
//示例
Generate(reflect.TypeOf(MyObject{}), nil)

备注:对Generate返回的Schema用json_marshal序列化后就可以得到json_schema

使用示例

type myDate struct {
	Day   string `json:"day,omitempty"`
	Month string `json:"month,omitempty"`
	Year  string `json:"year,omitempty"`
}
//生成无对象依赖的json-scheme
Generate(reflect.TypeOf(myDate{}), nil)
//生成有对象依赖的json-schema  Day对Month和Year有依赖
Generate(reflect.TypeOf(myDate{}), &Schema{Dependencies: map[string][]string{"day": {"month","year"}}})

特别说明:结构体中的field在json_schema中的属性对应的key为json的值,而required与json的子标签omitempty相关。例如:

type MyObject struct {
    ID     string  `json:"id,omitempty" required:"true"`
    Rate   float64 `json:"rate" required:"true"`
    Coords []int
}

生成的json

{
	"type": "object",
	"eo:type": "object",
	"properties": {
		"coords": {
			"type": "array",
			"eo:type": "array",
			"items": {
				"type": "integer",
				"eo:type": "integer",
				"format": "int32"
			}
		},
		"id": {
			"type": "string",
			"eo:type": "string"
		},
		"rate": {
			"type": "number",
			"eo:type": "number",
			"format": "double"
		}
	},
	"ui:sort": [
		"id",
		"rate",
		"coords"
	],
	"required": [
		"id",
		"rate"
	]
}

原支持的关键字

description

描述性关键字, 对数据进行说明描述

type Example struct {
	Foo string `json:"foo" description:"I am a test"`
}

default

描述性关键字,表示默认值,但这个关键字的值并不会在验证时填补空缺,仅作描述。

type Example struct {
	Foo string `json:"foo" default:"def"`
}

format

对字符串类型的值进行校验,type为非string的类型使用format仅作为注释,字符串类型支持的format如下:

  • "date-time" : 例如2018-11-13T20:20:39+00:00
  • "time":例如20:20:39+00:00
  • "date": 例如2018-11-13
  • "duration"
  • "email"
  • "idn-email"
  • "hostname"
  • "idn-hostname"
  • "ipv4"
  • "ipv6"
  • "uuid"
  • "uri"
  • "uri-reference"
  • "iri"
  • "iri-reference"
  • "uri-template"
  • "json-pointer"
  • "relative-json-pointer"
  • "regex"
type Example struct {
    Foo string `json:"foo" format:"date-time"`
}

enum

约束数据在枚举范围内进行取值

type ExampleONE struct {
    Foo string `json:"foo" enum:"one,two,three"`
}

type ExampleTWO struct {
    Foo []string `json:"foo" enum:"one,two,three"`
}

minimum

数值类型关键字,最小值,对数值取值范围的校验

type Example struct {
    Foo float64 `json:"foo" minimum:"1"`
}

maximum

数值类型关键字,最大值,数值取值范围的校验

type Example struct {
    Foo float64 `json:"foo" maximum:"0"`
}

exclusiveMinimum

数值类型关键字,开区间最小值

type Example struct {
    Foo float64 `json:"foo" exclusiveMinimum:"1"`
}

exclusiveMaximum

数值类型关键字,开区间最大值

type Example struct {
    Foo float64 `json:"foo" exclusiveMaximum:"0"`
}

multipleOf

数值类型关键字,该关键字可以校验 json 数据是否是给定条件数据的整数倍

type Example struct {
    Foo float64 `json:"foo" multipleOf:"10"` //表示foo需要能被10整除
}

minLength

字符串类型关键字,最小长度,用于约束字符串的长度

type Example struct {
	Foo string `json:"foo" minLength:"10"`
}

maxLength

字符串类型关键字,最大长度,用于约束字符串的长度

type Example struct {
    Foo string `json:"foo" maxLength:"10"`
}

pattern

字符串类型关键字,字符串正则表达式约束。

type Example struct {
    Foo string `json:"foo" pattern:"a-z+"`
}

minItems

数组类型关键字,定义数组的长度,最小长度

type Example struct {
    Foo []string `json:"foo" minItems:"10"`
}

maxItems

数组类型关键字,定义数组的长度,最大长度

type Example struct {
    Foo []string `json:"foo" maxItems:"10"`
}

uniqueItems

数组类型关键字,约束数组唯一性的关键字,即校验数组中的值均是唯一。

type Example struct {
    Foo []string `json:"foo" uniqueItems:"true"`
}

minProperties

object类型关键字,待校验的JSON对象中一级key的个数限制,minProperties指定了待校验的JSON对象可以接受的最少一级key的个数

type Bar struct{
    a int
    b int
}

type Example struct {
    Foo *Bar `json:"foo" minProperties:"2"`
}

maxProperties

object类型关键字,待校验的JSON对象中一级key的个数限制,maxProperties指定了待校验JSON对象可以接受的最多一级key的个数

type Bar struct{
    a int
    b int
}

type Example struct {
    Foo *Bar `json:"foo" maxProperties:"10"`
}

nullable

是否允许为空

type Example struct {
    Foo string `json:"foo" nullable:"true"`
}

readOnly

表示该数据只能作为响应的一部分被发送,而不应该作为请求的一部分被发送。若readOnly标签为true,同时该数据也在required 列表里,那么该数据的required标签只会在响应时生效。同时readOnlywriteOnly不能同时为true.

type Example struct {
    Foo string `json:"foo" readOnly:"true"`
}

writeOnly

表示该数据只能作为请求的一部分被发送,而不应该作为响应的一部分被发送。若readOnly标签为true,同时该数据也在required 列表里,那么该数据的required标签只会在请求时生效。同时readOnlywriteOnly不能同时为true.

type Example struct {
    Foo string `json:"foo" writeOnly:"true"`
}

deprecated

是否为废弃,表示该数据不应该被使用,或将来会被删除

type Example struct {
    Foo string `json:"foo" deprecated:"true"`
}

type

type不需要手动填写,会根据该struct field的类型去决定type。

required

表示值是否为必须

type Example struct {
	Foo string `json:"foo" required:"true"`
}

新增支持的关键字

dependencies

属于object类型的关键字,用于定义对象属性间的依赖关系。

注解规则及使用
type myDate struct {
    day   string  `json:"day,omitempty"`
    month string  `json:"month,omitempty"`
    year  string  `json:"year,omitempty"`
}

//MyObject内的Date属性依赖性表示:day存在则month和year均必须存在,month存在则year必须存在。
type MyObject struct {
	ID     string            `json:"id,omitempty" doc:"Object ID" readOnly:"true"`
	Rate   float64           `doc:"Rate of change" minimum:"0"`
	Coords []int             `doc:"X,Y coordinates" minItems:"2" maxItems:"2"`
	Date   myDate            `json:"date,omitempty" dependencies:"day:month;year month:year"`
	Bucket map[string]string `json:"bucket,omitempty" dependencies:"apple:banana;peach banana:melon"`
}

//调用Generate时传入携带dependencies的schema,可以对结构体或map的key进行依赖性校验
Generate(reflect.TypeOf(MyObject{}), &Schema{Dependencies: map[string][]string{"id": {"rate"}, "rate": {"coords", "date"}}})

属性直接用空格键 分割,单个属性内多个依赖属性用分号;分割

注意: dependencies标签只适用结构体和map

关键字说明

在该object中,若属性credit_card出现了,则属性billing_address也必须出现。

{
	"type": "object",
	"properties": [
        {
			"type": "string",
            "name": "name"
		},
		{
			"type": "number",
        	"name": "credit_card"
		},
		{
			"type": "string",
        	"name": "billing_address"
		}],
	"dependencies": {
		"credit_card": ["billing_address"] //单向约束
	}
}
/*	
"dependencies": {
	"credit_card": ["billing_address"], //双向约束
	"billing_address": ["credit_card"]
}
*/
//这个json是合法的
{
	"name": "John Doe",
	"credit_card": 123456,
	"billing_address": "555 Debtor's Lane"
}

//这个json是非法的
{
	"name": "John Doe",
    "credit_card": 123456
}

skill

自定义的关键字,用于指定target,upstream...的skill

注解规则及使用

注意:Target类型为eosc.RequiredId, 而eosc.RequiredId底层类型为string,如果不在标签指定type,则会被自动判断为string。

type Config struct {
	Id          string
	Name        string `json:"name"`
	Driver      string `json:"driver"`
    Target      RequireId   `json:"target" type:"requireid" skill: "github.com/eolinker/apinto/upstream.upstream.IUpstream"` 
}

转化json为:

{
    "type": "object",
    "properties": [
        {
            "name": "id",
            "type": "string"
        },
        {
            "name": "name",
            "type": "string"
        },
        {
            "name": "driver",
            "type": "string"
        },
        {
            "name": "target",
            "type": "require",
            "skill": "github.com/eolinker/apinto/upstream.upstream.IUpstream"
        }
    ]
}

switch

自定义的关键字,用于判断结构体中某个变量为特定值时才使当前变量生效

注解规则及使用

以下结构体表示以Schema和Health均以health_on为开关,当health_on为true时,health能够生效,schema不能生效; health_on为false时则相反。

type Config struct {
    Id          string 			  `json:"id"`
	Driver      string 			  `json:"driver"`
    Schema      string 			  `json:"schema" switch:"health_on=false"`
    HealthOn    bool 			  `json:"health_on"`
    Health      map[string]string `json:"health" switch:"health_on=true"`
}

转化json为:

{
	"type": "object",
	"properties": [
		{
			"name": "id",
			"type": "string"
		},
		{
			"name": "driver",
			"type": "string"
		},
		{
			"name": "schema",
			"type": "string",
			"switch": "health_on=false"
		},
		{
			"name": "health_on",
			"type": "boolean"
		},
		{
			"name": "health",
			"type": "map",
			"items": {
				"type": "string"
			},
			"switch": "health_on=true"
		}
	]
}

label

自定义的关键字,用于给变量赋予标签

注解规则及使用

label仅仅为字符串

type MyObject struct {
ID string `json:"id,omitempty" label:"myID"`
}

转化为json为:

{
	"type": "object",
	"properties": [
		{
			"name": "id",
			"type": "string",
			"label": "myID"
		}
	]
}

eo:type

自定义的关键字,用于给变量赋予eo类型

ui:sort

自定义的关键字,用于给properties排序

skip

自定义的关键字,兼容不导出schema,又需要使用到json标签的结构体字段。

Documentation

Overview

Package schema implements OpenAPI 3 compatible JSON Schema which can be generated from structs.

Example
type myDate struct {
	Day   string `json:"day,omitempty"`
	Month string `json:"month,omitempty"`
	Year  string `json:"year,omitempty"`
}

type MyObject struct {
	ID     string  `json:"id,omitempty" doc:"Object ID" readOnly:"true"`
	Rate   float64 `doc:"Rate of change" minimum:"0"`
	Coords []int   `doc:"X,Y coordinates" minItems:"2" maxItems:"2"`
	myDate `json:"date,omitempty" dependencies:"day:month;year month:year"`
	Bucket map[string]interface{} `json:"bucket,omitempty" dependencies:"apple:banana;peach banana:melon"`
	Target RequireId              `json:"target" skill:"github.com/eolinker/apinto/service.service.IService"`
}

generated, err := Generate(reflect.TypeOf(MyObject{}), nil)
if err != nil {
	panic(err)
}
bytes, _ := json.MarshalIndent(generated, "", "\t")
log.Debug(string(bytes))
Output:

{"type":"object","properties":{"bucket":{"type":"object","additionalProperties":{},"dependencies":{"apple":["banana","peach"],"banana":["melon"]}},"coords":{"type":"array","description":"X,Y coordinates","items":{"type":"integer","format":"int32"},"minItems":2,"maxItems":2},"date":{"type":"object","properties":{"day":{"type":"string"},"month":{"type":"string"},"year":{"type":"string"}},"additionalProperties":false,"dependencies":{"day":["month","year"],"month":["year"]}},"id":{"type":"string","description":"Object ID","readOnly":true},"rate":{"type":"number","description":"Rate of change","format":"double","minimum":0}},"additionalProperties":false,"required":["rate","coords"],"dependencies":{"id":["rate"],"rate":["coords","date"]}}

Index

Examples

Constants

View Source
const (
	TypeBoolean   = "boolean"
	TypeInteger   = "integer"
	TypeNumber    = "number"
	TypeString    = "string"
	TypeArray     = "array"
	TypeObject    = "object"
	TypeMap       = "map"
	TypeRequireId = "require"
	TypeFileList  = "eofiles"
	TypeFile      = "eofile"
	TypeFormatter = "formatter"
)

JSON Schema type constants

Variables

View Source
var ErrSchemaInvalid = errors.New("schema is invalid")

ErrSchemaInvalid is sent when there is a problem building the schema.

Functions

func F

func F(value float64) *float64

F returns a pointer to the given float64. Useful helper function for pointer schema validators like Maximum or Minimum.

func I

func I(value uint64) *uint64

I returns a pointer to the given int. Useful helper function for pointer schema validators like MaxLength or MinItems.

Types

type EoFile

type EoFile = eosc.GzipFile

type EoFileList

type EoFileList = eosc.EoFiles

type FormatterConfigType

type FormatterConfigType = eosc.FormatterConfig

type Mode

type Mode int

Mode defines whether the schema is being generated for read or write mode. Read-only fields are dropped when in write mode, for example.

const (
	// ModeAll is for general purpose use and includes all fields.
	ModeAll Mode = iota
	// ModeRead is for HTTP HEAD & GET and will hide write-only fields.
	ModeRead
	// ModeWrite is for HTTP POST, PUT, PATCH, DELETE and will hide
	// read-only fields.
	ModeWrite
)

type RequireId

type RequireId = eosc.RequireId

type Schema

type Schema struct {
	//Name                 string              `json:"name,omitempty"`
	Type                 string              `json:"type,omitempty"`
	EOType               string              `json:"eo:type,omitempty"`
	Description          string              `json:"description,omitempty"`
	Items                *Schema             `json:"items,omitempty"`
	Properties           map[string]*Schema  `json:"properties,omitempty"`
	AdditionalProperties *Schema             `json:"additionalProperties,omitempty"`
	UISort               []string            `json:"ui:sort,omitempty"`
	Required             []string            `json:"required,omitempty"`
	EmptyLabel           string              `json:"empty_label,omitempty"`
	Format               string              `json:"format,omitempty"`
	Enum                 []interface{}       `json:"enum,omitempty"`
	Default              interface{}         `json:"default,omitempty"`
	Example              interface{}         `json:"example,omitempty"`
	Minimum              *float64            `json:"minimum,omitempty"`
	ExclusiveMinimum     *bool               `json:"exclusiveMinimum,omitempty"`
	Maximum              *float64            `json:"maximum,omitempty"`
	ExclusiveMaximum     *bool               `json:"exclusiveMaximum,omitempty"`
	MultipleOf           float64             `json:"multipleOf,omitempty"`
	MinLength            *uint64             `json:"minLength,omitempty"`
	MaxLength            *uint64             `json:"maxLength,omitempty"`
	Pattern              string              `json:"pattern,omitempty"`
	MinItems             *uint64             `json:"minItems,omitempty"`
	MaxItems             *uint64             `json:"maxItems,omitempty"`
	UniqueItems          bool                `json:"uniqueItems,omitempty"`
	MinProperties        *uint64             `json:"minProperties,omitempty"`
	MaxProperties        *uint64             `json:"maxProperties,omitempty"`
	AllOf                []*Schema           `json:"allOf,omitempty"`
	AnyOf                []*Schema           `json:"anyOf,omitempty"`
	OneOf                []*Schema           `json:"oneOf,omitempty"`
	Not                  *Schema             `json:"not,omitempty"`
	Nullable             bool                `json:"nullable,omitempty"`
	ReadOnly             bool                `json:"readOnly,omitempty"`
	WriteOnly            bool                `json:"writeOnly,omitempty"`
	Deprecated           bool                `json:"deprecated,omitempty"`
	Ref                  string              `json:"$ref,omitempty"`
	Dependencies         map[string][]string `json:"dependencies,omitempty"`
	Skill                string              `json:"skill,omitempty"`
	Switch               string              `json:"switch,omitempty"`
	Label                string              `json:"label,omitempty"`
}

Schema represents a JSON Schema which can be generated from Go structs

func Generate

func Generate(t reflect.Type, dependencies map[string][]string) (*Schema, error)

Generate creates a JSON schema for a Go type. Struct field tags can be used to provide additional metadata such as descriptions and validation.

func (*Schema) HasValidation

func (s *Schema) HasValidation() bool

HasValidation returns true if at least one validator is set on the schema. This excludes the schema's type but includes most other fields and can be used to trigger additional slow validation steps when needed.

Jump to

Keyboard shortcuts

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